From f281bc64b20c6b58de35fec059802256b0aa26aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=81=9A=E4=B8=AA=E6=9C=89=E7=94=A8=E7=9A=84=E4=BA=BA?= <819389547@qq.com> Date: Wed, 12 Jun 2024 14:01:31 +0800 Subject: [PATCH] first commit --- .gitignore | 33 + LICENSE | 191 ++++ README.md | 83 ++ pom.xml | 321 ++++++ wjcy-common/pom.xml | 37 + .../zhengjie/annotation/AnonymousAccess.java | 30 + .../java/me/zhengjie/annotation/CheckPwd.java | 25 + .../zhengjie/annotation/DataPermission.java | 47 + .../java/me/zhengjie/annotation/DateTime.java | 31 + .../zhengjie/annotation/FormSubmission.java | 28 + .../java/me/zhengjie/annotation/Limit.java | 49 + .../java/me/zhengjie/annotation/Query.java | 90 ++ .../rest/AnonymousDeleteMapping.java | 91 ++ .../annotation/rest/AnonymousGetMapping.java | 90 ++ .../rest/AnonymousPatchMapping.java | 91 ++ .../annotation/rest/AnonymousPostMapping.java | 91 ++ .../annotation/rest/AnonymousPutMapping.java | 91 ++ .../java/me/zhengjie/aspect/LimitAspect.java | 99 ++ .../java/me/zhengjie/aspect/LimitType.java | 27 + .../main/java/me/zhengjie/base/BaseDTO.java | 40 + .../java/me/zhengjie/base/BaseEntity.java | 85 ++ .../java/me/zhengjie/base/BaseMapper.java | 53 + .../me/zhengjie/config/AuditorConfig.java | 45 + .../java/me/zhengjie/config/BeanFactory.java | 105 ++ .../me/zhengjie/config/CorsInterceptor.java | 36 + .../me/zhengjie/config/CustomIdGenerator.java | 39 + .../me/zhengjie/config/DhApiProperties.java | 58 + .../zhengjie/config/ElPermissionConfig.java | 37 + .../me/zhengjie/config/FileProperties.java | 60 ++ .../java/me/zhengjie/config/MvcConfig.java | 31 + .../zhengjie/config/MyMetaObjectHandler.java | 82 ++ .../me/zhengjie/config/MybatisPlusConfig.java | 32 + .../me/zhengjie/config/PlatsProperties.java | 44 + .../me/zhengjie/config/PropertiesConfig.java | 30 + .../java/me/zhengjie/config/RedisConfig.java | 223 ++++ .../me/zhengjie/config/RedissonConfig.java | 48 + .../me/zhengjie/config/RsaProperties.java | 38 + .../me/zhengjie/config/SwaggerConfig.java | 217 ++++ .../java/me/zhengjie/config/SystemConfig.java | 97 ++ .../me/zhengjie/config/YdApiProperties.java | 34 + .../zhengjie/config/constant/Constants.java | 30 + .../java/me/zhengjie/constant/Constants.java | 16 + .../me/zhengjie/constant/PublicConstant.java | 56 + .../main/java/me/zhengjie/dao/CtApplyDao.java | 39 + .../java/me/zhengjie/dao/CtBrowseDao.java | 61 ++ .../main/java/me/zhengjie/dao/CtBuyerDao.java | 56 + .../main/java/me/zhengjie/dao/CtCardDao.java | 34 + .../me/zhengjie/dao/CtClickFarmingDao.java | 90 ++ .../java/me/zhengjie/dao/CtClickOrderDao.java | 100 ++ .../java/me/zhengjie/dao/CtCompanyDao.java | 34 + .../main/java/me/zhengjie/dao/CtDhPayDao.java | 24 + .../main/java/me/zhengjie/dao/CtExcelDao.java | 17 + .../me/zhengjie/dao/CtExcelImportInfoDao.java | 17 + .../main/java/me/zhengjie/dao/CtOrderDao.java | 17 + .../java/me/zhengjie/dao/CtPlatformDao.java | 17 + .../main/java/me/zhengjie/dao/CtRebotDao.java | 41 + .../dao/CtResponseOrderAddressDao.java | 17 + .../me/zhengjie/dao/CtResponseOrderDao.java | 17 + .../dao/CtResponseOrderProductDao.java | 17 + .../main/java/me/zhengjie/dao/CtVpnDao.java | 35 + .../java/me/zhengjie/dao/DhAddCarDao.java | 61 ++ .../me/zhengjie/dao/DhAddCarOrderDao.java | 48 + .../java/me/zhengjie/dao/DhCarGoodsDao.java | 17 + .../main/java/me/zhengjie/dao/LoginIpDao.java | 17 + .../java/me/zhengjie/dao/SettingSiteDao.java | 17 + .../java/me/zhengjie/dao/SysQuartzJobDao.java | 26 + .../java/me/zhengjie/dao/SysQuartzLogDao.java | 23 + .../me/zhengjie/dao/mapper/CtDhPayService.xml | 12 + .../src/main/java/me/zhengjie/dto/Dto.java | 73 ++ .../main/java/me/zhengjie/dto/PageDTO.java | 49 + .../zhengjie/dto/StatementAggregateDTO.java | 38 + .../main/java/me/zhengjie/entity/CtApply.java | 73 ++ .../java/me/zhengjie/entity/CtBrowse.java | 45 + .../me/zhengjie/entity/CtBrowseYdParams.java | 33 + .../main/java/me/zhengjie/entity/CtBuyer.java | 103 ++ .../zhengjie/entity/CtBuyerClickSuccess.java | 19 + .../zhengjie/entity/CtBuyerContactInfo.java | 45 + .../me/zhengjie/entity/CtBuyerExport.java | 71 ++ .../zhengjie/entity/CtBuyerExportTemple.java | 67 ++ .../me/zhengjie/entity/CtBuyerImport.java | 84 ++ .../main/java/me/zhengjie/entity/CtCard.java | 80 ++ .../java/me/zhengjie/entity/CtCardExport.java | 40 + .../zhengjie/entity/CtCardExportTemple.java | 46 + .../java/me/zhengjie/entity/CtCardImport.java | 96 ++ .../java/me/zhengjie/entity/CtCardInfo.java | 22 + .../entity/CtClickFarmSupplyMentYdParams.java | 41 + .../zhengjie/entity/CtClickFarmYdParams.java | 59 ++ .../me/zhengjie/entity/CtClickFarming.java | 70 ++ .../zhengjie/entity/CtClickFarmingExport.java | 59 ++ .../entity/CtClickFarmingExportTemp.java | 53 + .../zhengjie/entity/CtClickFarmingImport.java | 64 ++ .../entity/CtClickFarmingOrderInfo.java | 37 + .../java/me/zhengjie/entity/CtClickOrder.java | 55 + .../zhengjie/entity/CtClickOrderExport.java | 37 + .../entity/CtClickOrderExportTemple.java | 39 + .../zhengjie/entity/CtClickOrderImport.java | 40 + .../zhengjie/entity/CtClickOrderYdParams.java | 33 + .../java/me/zhengjie/entity/CtCompany.java | 43 + .../me/zhengjie/entity/CtCompanyInfo.java | 23 + .../main/java/me/zhengjie/entity/CtDhPay.java | 44 + .../me/zhengjie/entity/CtDhPayExport.java | 29 + .../zhengjie/entity/CtDhPayExportTemple.java | 25 + .../me/zhengjie/entity/CtDhPayImport.java | 40 + .../main/java/me/zhengjie/entity/CtExcel.java | 41 + .../me/zhengjie/entity/CtExcelExportInfo.java | 40 + .../zhengjie/entity/CtExcelExportTemple.java | 33 + .../me/zhengjie/entity/CtExcelImportInfo.java | 59 ++ .../main/java/me/zhengjie/entity/CtOrder.java | 55 + .../zhengjie/entity/CtParamContactInfo.java | 39 + .../me/zhengjie/entity/CtParamProduct.java | 29 + .../java/me/zhengjie/entity/CtPlatform.java | 40 + .../main/java/me/zhengjie/entity/CtRebot.java | 41 + .../me/zhengjie/entity/CtRebotExport.java | 31 + .../zhengjie/entity/CtRebotExportTemple.java | 24 + .../me/zhengjie/entity/CtRebotImport.java | 43 + .../me/zhengjie/entity/CtResponseOrder.java | 67 ++ .../entity/CtResponseOrderAddress.java | 53 + .../entity/CtResponseOrderProduct.java | 96 ++ .../me/zhengjie/entity/CtSettingSite.java | 43 + .../main/java/me/zhengjie/entity/CtVpn.java | 55 + .../java/me/zhengjie/entity/CtVpnExport.java | 45 + .../me/zhengjie/entity/CtVpnExportTemple.java | 43 + .../java/me/zhengjie/entity/CtVpnImport.java | 66 ++ .../java/me/zhengjie/entity/CtVpnInfo.java | 23 + .../java/me/zhengjie/entity/DhAddCar.java | 48 + .../me/zhengjie/entity/DhAddCarOrder.java | 55 + .../java/me/zhengjie/entity/DhCarGoods.java | 62 ++ .../me/zhengjie/entity/ExcelImportInfo.java | 38 + .../main/java/me/zhengjie/entity/LoginIp.java | 39 + .../zhengjie/entity/QueryWrapperAndPage.java | 15 + .../java/me/zhengjie/entity/ResultObj.java | 20 + .../java/me/zhengjie/entity/ReturnObje.java | 28 + .../java/me/zhengjie/entity/SysQuartzJob.java | 70 ++ .../java/me/zhengjie/entity/SysQuartzLog.java | 58 + .../main/java/me/zhengjie/entity/YdSign.java | 32 + .../me/zhengjie/entity/YdStartReturn.java | 24 + .../java/me/zhengjie/entity/quartz/Boss.java | 23 + .../me/zhengjie/entity/quartz/DataInfo.java | 19 + .../entity/quartz/JobQueryByUuid.java | 18 + .../entity/quartz/JobQueryByUuidData.java | 28 + .../entity/quartz/JobQueryByUuidReturn.java | 93 ++ .../quartz/JobQueryByUuidRobotParams.java | 22 + .../entity/quartz/JobQueryReturnResult.java | 22 + .../java/me/zhengjie/entity/quartz/Param.java | 20 + .../me/zhengjie/entity/quartz/Params.java | 22 + .../me/zhengjie/entity/quartz/RebotStatu.java | 19 + .../entity/quartz/RebotStatuInfo.java | 29 + .../entity/quartz/RebotStatuReturn.java | 20 + .../me/zhengjie/entity/quartz/SecreInfo.java | 21 + .../entity/quartz/StartYdReturnInfo.java | 22 + .../me/zhengjie/enums/BuyerLevelEnum.java | 77 ++ .../zhengjie/enums/BuyerOccupyStatusEnum.java | 75 ++ .../me/zhengjie/enums/BuyerStatusEnum.java | 80 ++ .../me/zhengjie/enums/CardDealerTypeEnum.java | 75 ++ .../me/zhengjie/enums/CardStatusEnum.java | 76 ++ .../java/me/zhengjie/enums/CardTypeEnum.java | 76 ++ .../zhengjie/enums/ClickBrowseStatusEnum.java | 77 ++ .../enums/ClickFarmingStatusEnum.java | 79 ++ .../zhengjie/enums/ClickOrderStatusEnum.java | 77 ++ .../me/zhengjie/enums/CtReboteStatusEnum.java | 75 ++ .../me/zhengjie/enums/DhAddCarStatusEnum.java | 82 ++ .../me/zhengjie/enums/DhPayStatusEnum.java | 77 ++ .../enums/ExcelInfoRequestTypeEnum.java | 75 ++ .../me/zhengjie/enums/ExcelStatusEnum.java | 76 ++ .../java/me/zhengjie/enums/LanguageEnum.java | 38 + .../java/me/zhengjie/enums/OrderTypeEnum.java | 75 ++ .../me/zhengjie/enums/ParamsTypeEnum.java | 75 ++ .../java/me/zhengjie/enums/PlatTypeEnum.java | 92 ++ .../me/zhengjie/enums/RobotStatusEnum.java | 77 ++ .../java/me/zhengjie/enums/TaskInfoEnum.java | 54 + .../me/zhengjie/enums/TaskIsPauseEnum.java | 75 ++ .../java/me/zhengjie/enums/TaskTypeEnum.java | 75 ++ .../java/me/zhengjie/enums/VpnDealerEnum.java | 74 ++ .../java/me/zhengjie/enums/VpnStatusEnum.java | 75 ++ .../java/me/zhengjie/enums/VpnTypeEnum.java | 74 ++ .../java/me/zhengjie/enums/YesOrNoEnum.java | 75 ++ .../enums/interfaces/IntegerEnum.java | 40 + .../zhengjie/enums/interfaces/LongEnum.java | 40 + .../enums/interfaces/MemberIsUsedEnum.java | 71 ++ .../java/me/zhengjie/error/ErrorCodeEnum.java | 143 +++ .../exception/BadConfigurationException.java | 98 ++ .../exception/BadRequestException.java | 50 + .../exception/EntityExistException.java | 34 + .../exception/EntityNotFoundException.java | 34 + .../zhengjie/exception/handler/ApiError.java | 52 + .../handler/GlobalExceptionHandler.java | 197 ++++ .../mybatis/LambdaQueryWrapperImpl.java | 29 + .../me/zhengjie/service/CtApplyService.java | 42 + .../me/zhengjie/service/CtBrowseService.java | 41 + .../me/zhengjie/service/CtBuyerService.java | 50 + .../me/zhengjie/service/CtCardService.java | 26 + .../service/CtClickFarmingService.java | 36 + .../zhengjie/service/CtClickOrderService.java | 65 ++ .../me/zhengjie/service/CtCompanyService.java | 34 + .../me/zhengjie/service/CtDhPayService.java | 29 + .../service/CtExcelImportInfoService.java | 23 + .../me/zhengjie/service/CtExcelService.java | 15 + .../me/zhengjie/service/CtOrderService.java | 31 + .../zhengjie/service/CtPlatformService.java | 24 + .../me/zhengjie/service/CtRebotService.java | 63 ++ .../CtResponseOrderAddressService.java | 17 + .../CtResponseOrderProductService.java | 17 + .../service/CtResponseOrderService.java | 17 + .../me/zhengjie/service/CtVpnService.java | 24 + .../service/DhAddCarOrderService.java | 41 + .../me/zhengjie/service/DhAddCarService.java | 49 + .../zhengjie/service/DhCarGoodsService.java | 15 + .../zhengjie/service/FileUploadService.java | 20 + .../me/zhengjie/service/LoginIpService.java | 58 + .../zhengjie/service/SettingSiteService.java | 25 + .../zhengjie/service/SysQuartzLogService.java | 21 + .../me/zhengjie/service/YdQuartzService.java | 74 ++ .../service/impl/CtApplyServiceImpl.java | 44 + .../service/impl/CtBrowseServiceImpl.java | 44 + .../service/impl/CtBuyerServiceImpl.java | 69 ++ .../service/impl/CtCardServiceImpl.java | 33 + .../impl/CtClickFarmingServiceImpl.java | 62 ++ .../service/impl/CtClickOrderServiceImpl.java | 90 ++ .../service/impl/CtCompanyServiceImpl.java | 53 + .../service/impl/CtDhPayServiceImpl.java | 100 ++ .../impl/CtExcelImportInfoServiceImpl.java | 174 +++ .../service/impl/CtExcelServiceImpl.java | 19 + .../service/impl/CtOrderServiceImpl.java | 196 ++++ .../service/impl/CtPlatformServiceImpl.java | 37 + .../service/impl/CtRebotServiceImpl.java | 127 +++ .../CtResponseOrderAddressServiceImpl.java | 19 + .../CtResponseOrderProductServiceImpl.java | 19 + .../impl/CtResponseOrderServiceImpl.java | 19 + .../service/impl/CtVpnServiceImpl.java | 31 + .../impl/DhAddCarOrderServiceImpl.java | 98 ++ .../service/impl/DhAddCarServiceImpl.java | 108 ++ .../service/impl/DhCarGoodsServiceImpl.java | 19 + .../service/impl/FileUploadServiceImpl.java | 130 +++ .../service/impl/LoginIpServiceImpl.java | 121 +++ .../service/impl/SettingSiteServiceImpl.java | 75 ++ .../service/impl/SysQuartzJobServiceImpl.java | 63 ++ .../service/impl/SysQuartzLogServiceImpl.java | 35 + .../service/impl/YdQuartzServiceImpl.java | 464 ++++++++ .../service/redission/LockCallBack.java | 8 + .../service/vo/AdminGoogleAuthInfoVO.java | 31 + .../service/vo/BuyOrderResponseAddressVO.java | 39 + .../service/vo/BuyOrderResponseOrderVO.java | 54 + .../service/vo/BuyOrderResponseProductVO.java | 81 ++ .../me/zhengjie/service/vo/BuyOrderVO.java | 24 + .../me/zhengjie/service/vo/CtApplyInfoVO.java | 19 + .../me/zhengjie/service/vo/CtApplyListVO.java | 68 ++ .../zhengjie/service/vo/CtBrowseDetailVO.java | 73 ++ .../zhengjie/service/vo/CtBrowseListVO.java | 63 ++ .../service/vo/CtBuyerClickFarmVO.java | 103 ++ .../zhengjie/service/vo/CtBuyerDetailVO.java | 162 +++ .../me/zhengjie/service/vo/CtBuyerListVO.java | 111 ++ .../me/zhengjie/service/vo/CtBuyerVO.java | 47 + .../zhengjie/service/vo/CtCardDetailVO.java | 125 +++ .../me/zhengjie/service/vo/CtCardListVO.java | 72 ++ .../service/vo/CtClickFarmEditDetailVO.java | 63 ++ .../service/vo/CtClickFarmingDetailVO.java | 98 ++ .../zhengjie/service/vo/CtClickFarmingVO.java | 59 ++ .../service/vo/CtClickOrderDetailVO.java | 48 + .../service/vo/CtClickOrderListVO.java | 45 + .../zhengjie/service/vo/CtCompanyInfoVO.java | 23 + .../me/zhengjie/service/vo/CtCompanyVO.java | 35 + .../zhengjie/service/vo/CtDhPayDetailVO.java | 40 + .../me/zhengjie/service/vo/CtDhPayListVO.java | 36 + .../service/vo/CtExcelImportInfoVO.java | 42 + .../me/zhengjie/service/vo/CtExcelVO.java | 31 + .../me/zhengjie/service/vo/CtOrderVO.java | 44 + .../zhengjie/service/vo/CtPlatformInfoVO.java | 23 + .../me/zhengjie/service/vo/CtPlatformVO.java | 29 + .../me/zhengjie/service/vo/CtRebotListVO.java | 37 + .../me/zhengjie/service/vo/CtVpnInfoVO.java | 16 + .../java/me/zhengjie/service/vo/CtVpnVO.java | 42 + .../zhengjie/service/vo/GoogleAuthInfoVO.java | 27 + .../me/zhengjie/service/vo/LoginIpVO.java | 57 + .../service/vo/OrderResponStatusVO.java | 21 + .../service/vo/OrderResponSubErrorVO.java | 19 + .../zhengjie/service/vo/OrderResponseVO.java | 28 + .../me/zhengjie/service/vo/PayOrderVO.java | 23 + .../me/zhengjie/service/vo/SettingSiteVO.java | 31 + .../service/vo/SysQuartzJobListVO.java | 40 + .../service/vo/SysQuartzLogListVO.java | 47 + .../service/vo/dhaddcar/DhAddCarListVO.java | 80 ++ .../service/vo/dhaddcar/DhAddCarVO.java | 65 ++ .../vo/dhaddcar/DhAddCarYdParamsVO.java | 56 + .../service/vo/dhcargood/DhCarGoodKeyVO.java | 76 ++ .../service/vo/dhcargood/DhCarGoodLinkVO.java | 56 + .../vo/dhcarorder/DhAddCarOrderListVO.java | 62 ++ .../vo/dhcarorder/DhCarOrderParamsVO.java | 59 ++ .../main/java/me/zhengjie/utils/CacheKey.java | 58 + .../main/java/me/zhengjie/utils/CallBack.java | 43 + .../me/zhengjie/utils/CheckPwdValidator.java | 35 + .../java/me/zhengjie/utils/CloseUtil.java | 47 + .../java/me/zhengjie/utils/CronUtils.java | 49 + .../me/zhengjie/utils/DateTimeValidator.java | 46 + .../main/java/me/zhengjie/utils/DateUtil.java | 555 ++++++++++ .../me/zhengjie/utils/ElAdminConstant.java | 47 + .../zhengjie/utils/EmptyAttributeFiler.java | 76 ++ .../java/me/zhengjie/utils/EncryptUtils.java | 100 ++ .../main/java/me/zhengjie/utils/FileUtil.java | 351 +++++++ .../main/java/me/zhengjie/utils/HexUtil.java | 51 + .../me/zhengjie/utils/HttpClientUtil.java | 356 +++++++ .../zhengjie/utils/HttpConnectionManager.java | 57 + .../java/me/zhengjie/utils/JsonDealUtils.java | 54 + .../java/me/zhengjie/utils/LoginIpUtil.java | 88 ++ .../main/java/me/zhengjie/utils/MD5Util.java | 125 +++ .../me/zhengjie/utils/OrderGetIndexUtil.java | 63 ++ .../main/java/me/zhengjie/utils/PageUtil.java | 63 ++ .../java/me/zhengjie/utils/PageUtils.java | 55 + .../me/zhengjie/utils/PopularizeUtil.java | 49 + .../me/zhengjie/utils/PropertiesUtil.java | 62 ++ .../java/me/zhengjie/utils/QueryHelp.java | 208 ++++ .../java/me/zhengjie/utils/RedisUtils.java | 903 ++++++++++++++++ .../java/me/zhengjie/utils/RedissonUtil.java | 167 +++ .../java/me/zhengjie/utils/RequestHolder.java | 50 + .../main/java/me/zhengjie/utils/RsaUtils.java | 202 ++++ .../java/me/zhengjie/utils/SecurityUtils.java | 109 ++ .../zhengjie/utils/SpringContextHolder.java | 151 +++ .../java/me/zhengjie/utils/StringUtil.java | 200 ++++ .../java/me/zhengjie/utils/StringUtils.java | 332 ++++++ .../java/me/zhengjie/utils/ThrowableUtil.java | 37 + .../java/me/zhengjie/utils/TransformMap.java | 60 ++ .../zhengjie/utils/TransformQueryWrapper.java | 165 +++ .../me/zhengjie/utils/TranslatorUtil.java | 66 ++ .../me/zhengjie/utils/ValidationUtil.java | 126 +++ .../me/zhengjie/utils/YdCallBackUtil.java | 89 ++ .../java/me/zhengjie/utils/YdParamsCheck.java | 54 + .../java/me/zhengjie/utils/YdSignUtil.java | 94 ++ .../me/zhengjie/utils/enums/CodeBiEnum.java | 50 + .../me/zhengjie/utils/enums/CodeEnum.java | 46 + .../zhengjie/utils/enums/DataScopeEnum.java | 53 + .../utils/enums/RequestMethodEnum.java | 74 ++ .../zhengjie/utils/excel/ExcelClassField.java | 79 ++ .../me/zhengjie/utils/excel/ExcelExport.java | 30 + .../me/zhengjie/utils/excel/ExcelImport.java | 34 + .../me/zhengjie/utils/excel/ExcelUtils.java | 993 ++++++++++++++++++ .../me/zhengjie/utils/EncryptUtilsTest.java | 32 + .../java/me/zhengjie/utils/FileUtilTest.java | 36 + .../me/zhengjie/utils/StringUtilsTest.java | 66 ++ wjcy-generator/pom.xml | 39 + .../java/me/zhengjie/domain/ColumnInfo.java | 97 ++ .../java/me/zhengjie/domain/GenConfig.java | 78 ++ .../java/me/zhengjie/domain/vo/TableInfo.java | 48 + .../repository/ColumnInfoRepository.java | 34 + .../repository/GenConfigRepository.java | 33 + .../me/zhengjie/rest/GenConfigController.java | 51 + .../me/zhengjie/rest/GeneratorController.java | 107 ++ .../me/zhengjie/service/GenConfigService.java | 40 + .../me/zhengjie/service/GeneratorService.java | 96 ++ .../service/impl/GenConfigServiceImpl.java | 67 ++ .../service/impl/GeneratorServiceImpl.java | 203 ++++ .../main/java/me/zhengjie/utils/ColUtil.java | 54 + .../main/java/me/zhengjie/utils/GenUtil.java | 420 ++++++++ wjcy-logging/pom.xml | 22 + .../main/java/me/zhengjie/annotation/Log.java | 55 + .../annotation/type/LogActionType.java | 34 + .../zhengjie/annotation/type/LogDaoType.java | 30 + .../annotation/type/LogGetIdType.java | 36 + .../annotation/type/LogGetValueType.java | 32 + .../java/me/zhengjie/aspect/LogAspect.java | 98 ++ .../src/main/java/me/zhengjie/domain/Log.java | 95 ++ .../java/me/zhengjie/enums/LogTypeEnum.java | 33 + .../me/zhengjie/repository/LogRepository.java | 49 + .../java/me/zhengjie/rest/LogController.java | 157 +++ .../java/me/zhengjie/service/LogService.java | 101 ++ .../me/zhengjie/service/dto/LogErrorDTO.java | 46 + .../service/dto/LogQueryCriteria.java | 42 + .../me/zhengjie/service/dto/LogSmallDTO.java | 40 + .../zhengjie/service/impl/LogServiceImpl.java | 232 ++++ .../service/mapstruct/LogErrorMapper.java | 31 + .../service/mapstruct/LogSmallMapper.java | 31 + wjcy-system/pom.xml | 128 +++ .../src/main/java/me/zhengjie/AppRun.java | 70 ++ .../zhengjie/aspect/FormSubmissionAspect.java | 93 ++ .../me/zhengjie/config/ConfigurerAdapter.java | 88 ++ .../java/me/zhengjie/config/CorsConfig.java | 20 + .../zhengjie/config/GoogleAuthProperties.java | 58 + .../me/zhengjie/config/WebSocketConfig.java | 33 + .../config/thread/AsyncTaskExecutePool.java | 69 ++ .../config/thread/AsyncTaskProperties.java | 39 + .../config/thread/TheadFactoryName.java | 63 ++ .../config/thread/ThreadPoolExecutorUtil.java | 42 + .../me/zhengjie/modules/aspect/LogAspect.java | 154 +++ .../controller/FileUploadController.java | 51 + .../controller/GoogleAuthController.java | 144 +++ .../capital/controller/LoginIpController.java | 68 ++ .../controller/SettingSiteController.java | 140 +++ .../modules/capital/dto/AddLoginIpDTO.java | 50 + .../modules/capital/dto/EditLoginIpDTO.java | 26 + .../zhengjie/modules/capital/dto/IdDTO.java | 17 + .../capital/dto/RelSettingSiteDTO.java | 27 + .../modules/capital/dto/SettingSiteDTO.java | 33 + .../controller/base/CtApplyController.java | 187 ++++ .../controller/base/CtBrowseController.java | 148 +++ .../controller/base/CtBuyerController.java | 391 +++++++ .../controller/base/CtCardController.java | 307 ++++++ .../base/CtClickFarmingController.java | 301 ++++++ .../base/CtClickOrderController.java | 330 ++++++ .../controller/base/CtCompanyController.java | 187 ++++ .../controller/base/CtDhPayController.java | 300 ++++++ .../controller/base/CtExcelController.java | 157 +++ .../base/CtExcelInfoController.java | 120 +++ .../controller/base/CtOrderController.java | 165 +++ .../controller/base/CtPlatformController.java | 136 +++ .../controller/base/CtRebotController.java | 214 ++++ .../controller/base/CtVpnController.java | 261 +++++ .../base/DhAddCarCatchController.java | 409 ++++++++ .../controller/base/DhAddCarController.java | 466 ++++++++ .../base/DhAddCarOrderController.java | 57 + .../controller/base/QuartzLogController.java | 55 + .../group/controller/base/SdsController.java | 320 ++++++ .../base/SysQuartzJobController.java | 206 ++++ .../controller/base/YdCallBackController.java | 122 +++ .../callbcak/BossTaskCallBackController.java | 84 ++ .../ClickFarmingCallBackController.java | 432 ++++++++ ...ckFarmingSuppleMentCallBackController.java | 234 +++++ .../ClickOrderCallBackController.java | 151 +++ .../callbcak/CtbrowseCallBackController.java | 148 +++ .../callbcak/DhAddCarCallBackController.java | 152 +++ .../DhCarOrderCallBackController.java | 170 +++ .../DhCatchOrderCallBackController.java | 166 +++ .../modules/group/dto/CtApplyAddDTO.java | 57 + .../modules/group/dto/CtApplyListDTO.java | 43 + .../modules/group/dto/CtApplyUpdateDTO.java | 54 + .../modules/group/dto/CtBrowseAddDTO.java | 33 + .../modules/group/dto/CtBrowseListDTO.java | 57 + .../modules/group/dto/CtBrowseUpdateDTO.java | 46 + .../modules/group/dto/CtBuyerAddDTO.java | 135 +++ .../modules/group/dto/CtBuyerListDTO.java | 57 + .../modules/group/dto/CtBuyerUpdateDTO.java | 122 +++ .../modules/group/dto/CtCardAddDTO.java | 105 ++ .../modules/group/dto/CtCardListDTO.java | 62 ++ .../modules/group/dto/CtCardUpdateDTO.java | 75 ++ .../group/dto/CtClickFarmingAddDTO.java | 83 ++ .../modules/group/dto/CtClickFarmingDTO.java | 87 ++ .../group/dto/CtClickFarmingEditDTO.java | 84 ++ .../modules/group/dto/CtClickOrderAddDto.java | 71 ++ .../group/dto/CtClickOrderCommentDto.java | 34 + .../group/dto/CtClickOrderListDTO.java | 69 ++ .../group/dto/CtClickOrderSupplementDto.java | 58 + .../modules/group/dto/CtCompanyAddDTO.java | 29 + .../modules/group/dto/CtCompanyListDTO.java | 47 + .../modules/group/dto/CtCompanyUpdateDTO.java | 30 + .../modules/group/dto/CtDhPayAddDTO.java | 30 + .../modules/group/dto/CtDhPayListDTO.java | 39 + .../modules/group/dto/CtExcelAddDTO.java | 27 + .../group/dto/CtExcelImportInfoListDTO.java | 41 + .../modules/group/dto/CtExcelListDTO.java | 40 + .../modules/group/dto/CtExcelUpdateDTO.java | 27 + .../modules/group/dto/CtOrderListDTO.java | 42 + .../modules/group/dto/CtPlatformAddDTO.java | 25 + .../modules/group/dto/CtPlatformListDTO.java | 39 + .../group/dto/CtPlatformUpdateDTO.java | 31 + .../modules/group/dto/CtRebotAddDTO.java | 26 + .../modules/group/dto/CtRebotListDTO.java | 42 + .../modules/group/dto/CtRebotUpdateDTO.java | 33 + .../group/dto/CtRebotUpdateStatusDTO.java | 24 + .../modules/group/dto/CtVpnAddDTO.java | 50 + .../modules/group/dto/CtVpnListDTO.java | 59 ++ .../modules/group/dto/CtVpnUpdateDTO.java | 43 + .../group/dto/DhCarGoodWellReceivedDTO.java | 30 + .../group/dto/DhCarWellReceivedDTO.java | 29 + .../me/zhengjie/modules/group/dto/IdDTO.java | 22 + .../modules/group/dto/SearchOrderListDTO.java | 69 ++ .../modules/group/dto/SysQuartzJobAddDTO.java | 54 + .../group/dto/SysQuartzJobListDTO.java | 43 + .../group/dto/SysQuartzJobUpdateDTO.java | 49 + .../group/dto/SysQuartzLogListDTO.java | 42 + .../group/dto/dhaddcar/DhAddCarAddDTO.java | 46 + .../group/dto/dhaddcar/DhAddCarEditDTO.java | 48 + .../group/dto/dhaddcar/DhAddCarListDTO.java | 73 ++ .../dto/dhcargood/DhCarGoodKeyAddDTO.java | 70 ++ .../dto/dhcargood/DhCarGoodKeyEditDTO.java | 74 ++ .../dto/dhcargood/DhCarGoodLinkAddDTO.java | 49 + .../dto/dhcargood/DhCarGoodLinkEditDTO.java | 53 + .../dto/dhcarorder/DhAddCarOrderListDTO.java | 66 ++ .../me/zhengjie/modules/mnt/domain/App.java | 67 ++ .../zhengjie/modules/mnt/domain/Database.java | 57 + .../zhengjie/modules/mnt/domain/Deploy.java | 59 ++ .../modules/mnt/domain/DeployHistory.java | 62 ++ .../modules/mnt/domain/ServerDeploy.java | 80 ++ .../modules/mnt/repository/AppRepository.java | 27 + .../mnt/repository/DatabaseRepository.java | 27 + .../repository/DeployHistoryRepository.java | 27 + .../mnt/repository/DeployRepository.java | 27 + .../repository/ServerDeployRepository.java | 34 + .../modules/mnt/rest/AppController.java | 87 ++ .../modules/mnt/rest/DatabaseController.java | 123 +++ .../modules/mnt/rest/DeployController.java | 153 +++ .../mnt/rest/DeployHistoryController.java | 67 ++ .../mnt/rest/ServerDeployController.java | 95 ++ .../modules/mnt/service/AppService.java | 81 ++ .../modules/mnt/service/DatabaseService.java | 88 ++ .../mnt/service/DeployHistoryService.java | 74 ++ .../modules/mnt/service/DeployService.java | 116 ++ .../mnt/service/ServerDeployService.java | 95 ++ .../modules/mnt/service/dto/AppDto.java | 71 ++ .../mnt/service/dto/AppQueryCriteria.java | 38 + .../modules/mnt/service/dto/DatabaseDto.java | 55 + .../service/dto/DatabaseQueryCriteria.java | 44 + .../modules/mnt/service/dto/DeployDto.java | 78 ++ .../mnt/service/dto/DeployHistoryDto.java | 58 + .../dto/DeployHistoryQueryCriteria.java | 41 + .../mnt/service/dto/DeployQueryCriteria.java | 39 + .../mnt/service/dto/ServerDeployDto.java | 61 ++ .../dto/ServerDeployQueryCriteria.java | 38 + .../mnt/service/impl/AppServiceImpl.java | 123 +++ .../mnt/service/impl/DatabaseServiceImpl.java | 117 +++ .../impl/DeployHistoryServiceImpl.java | 96 ++ .../mnt/service/impl/DeployServiceImpl.java | 430 ++++++++ .../service/impl/ServerDeployServiceImpl.java | 125 +++ .../mnt/service/mapstruct/AppMapper.java | 31 + .../mnt/service/mapstruct/DatabaseMapper.java | 31 + .../mapstruct/DeployHistoryMapper.java | 31 + .../mnt/service/mapstruct/DeployMapper.java | 31 + .../service/mapstruct/ServerDeployMapper.java | 31 + .../modules/mnt/util/DataTypeEnum.java | 140 +++ .../modules/mnt/util/ExecuteShellUtil.java | 101 ++ .../modules/mnt/util/ScpClientUtil.java | 105 ++ .../zhengjie/modules/mnt/util/SqlUtils.java | 201 ++++ .../modules/mnt/websocket/MsgType.java | 31 + .../modules/mnt/websocket/SocketMsg.java | 33 + .../mnt/websocket/WebSocketServer.java | 139 +++ .../modules/quartz/config/JobRunner.java | 54 + .../modules/quartz/config/QuartzConfig.java | 52 + .../modules/quartz/domain/QuartzJob.java | 92 ++ .../modules/quartz/domain/QuartzLog.java | 70 ++ .../repository/QuartzJobRepository.java | 34 + .../repository/QuartzLogRepository.java | 28 + .../quartz/rest/QuartzJobController.java | 127 +++ .../quartz/service/QuartzJobService.java | 128 +++ .../quartz/service/SysQuartzJobService.java | 77 ++ .../quartz/service/dto/JobQueryCriteria.java | 41 + .../service/impl/QuartzJobServiceImpl.java | 205 ++++ .../service/impl/SysQuartzJobServiceImpl.java | 521 +++++++++ .../modules/quartz/task/BossTask.java | 51 + .../modules/quartz/task/BossTask22.java | 165 +++ .../modules/quartz/task/BrowseTask.java | 54 + .../quartz/task/ClickFarmSuppleMentTask.java | 54 + .../modules/quartz/task/ClickFarmTask.java | 54 + .../modules/quartz/task/DhAddCarTask.java | 54 + .../modules/quartz/task/DhCatchOrderTask.java | 54 + .../modules/quartz/task/DhPayTask.java | 47 + .../quartz/task/DhWellReceivedTask.java | 54 + .../modules/quartz/task/ExcelToOrderTask.java | 46 + .../modules/quartz/task/ExcelmportTask.java | 46 + .../modules/quartz/task/OrderToPayTask.java | 46 + .../modules/quartz/task/RebotStatusTask.java | 95 ++ .../modules/quartz/task/TestTask.java | 49 + .../modules/quartz/task/WellReceivedTask.java | 55 + .../modules/quartz/utils/ExecutionJob.java | 140 +++ .../modules/quartz/utils/QuartzManage.java | 174 +++ .../modules/quartz/utils/QuartzRunnable.java | 58 + .../modules/quartz/utils/YdApiUtil.java | 31 + .../config/ConfigBeanConfiguration.java | 43 + .../security/config/SecurityConfig.java | 207 ++++ .../security/config/bean/LoginCode.java | 61 ++ .../security/config/bean/LoginCodeEnum.java | 43 + .../security/config/bean/LoginProperties.java | 135 +++ .../config/bean/SecurityProperties.java | 72 ++ .../rest/AuthorizationController.java | 201 ++++ .../security/rest/OnlineController.java | 68 ++ .../security/JwtAccessDeniedHandler.java | 37 + .../security/JwtAuthenticationEntryPoint.java | 39 + .../security/security/TokenConfigurer.java | 45 + .../security/security/TokenFilter.java | 111 ++ .../security/security/TokenProvider.java | 123 +++ .../security/service/OnlineUserService.java | 191 ++++ .../security/service/UserCacheClean.java | 49 + .../service/UserDetailsServiceImpl.java | 94 ++ .../security/service/dto/AuthUserDto.java | 39 + .../security/service/dto/JwtUserDto.java | 82 ++ .../security/service/dto/OnlineUserDto.java | 73 ++ .../zhengjie/modules/system/domain/Dept.java | 86 ++ .../zhengjie/modules/system/domain/Dict.java | 54 + .../modules/system/domain/DictDetail.java | 56 + .../zhengjie/modules/system/domain/Job.java | 73 ++ .../zhengjie/modules/system/domain/Menu.java | 110 ++ .../zhengjie/modules/system/domain/Role.java | 99 ++ .../zhengjie/modules/system/domain/User.java | 129 +++ .../modules/system/domain/vo/MenuMetaVo.java | 35 + .../modules/system/domain/vo/MenuVo.java | 47 + .../modules/system/domain/vo/UserPassVo.java | 37 + .../system/repository/DeptRepository.java | 69 ++ .../repository/DictDetailRepository.java | 36 + .../system/repository/DictRepository.java | 43 + .../system/repository/JobRepository.java | 42 + .../system/repository/MenuRepository.java | 85 ++ .../system/repository/RoleRepository.java | 80 ++ .../system/repository/UserRepository.java | 130 +++ .../modules/system/rest/DeptController.java | 117 +++ .../modules/system/rest/DictController.java | 99 ++ .../system/rest/DictDetailController.java | 99 ++ .../modules/system/rest/JobController.java | 94 ++ .../modules/system/rest/LimitController.java | 47 + .../modules/system/rest/MenuController.java | 147 +++ .../system/rest/MonitorController.java | 45 + .../modules/system/rest/RoleController.java | 154 +++ .../modules/system/rest/UserController.java | 230 ++++ .../modules/system/rest/VerifyController.java | 76 ++ .../modules/system/service/DataService.java | 34 + .../modules/system/service/DeptService.java | 124 +++ .../system/service/DictDetailService.java | 63 ++ .../modules/system/service/DictService.java | 75 ++ .../modules/system/service/JobService.java | 93 ++ .../modules/system/service/MenuService.java | 125 +++ .../system/service/MonitorService.java | 31 + .../modules/system/service/RoleService.java | 136 +++ .../modules/system/service/UserService.java | 116 ++ .../modules/system/service/VerifyService.java | 41 + .../modules/system/service/dto/DeptDto.java | 78 ++ .../system/service/dto/DeptQueryCriteria.java | 46 + .../system/service/dto/DeptSmallDto.java | 31 + .../system/service/dto/DictDetailDto.java | 40 + .../service/dto/DictDetailQueryCriteria.java | 33 + .../modules/system/service/dto/DictDto.java | 39 + .../system/service/dto/DictQueryCriteria.java | 30 + .../system/service/dto/DictSmallDto.java | 31 + .../system/service/dto/GoogleAuthCodeDTO.java | 27 + .../service/dto/GoogleAuthGenSecretDTO.java | 23 + .../dto/GoogleAuthQrBarCodeUrlDTO.java | 23 + .../modules/system/service/dto/JobDto.java | 46 + .../system/service/dto/JobQueryCriteria.java | 40 + .../system/service/dto/JobSmallDto.java | 33 + .../modules/system/service/dto/MenuDto.java | 91 ++ .../system/service/dto/MenuQueryCriteria.java | 41 + .../modules/system/service/dto/RoleDto.java | 63 ++ .../system/service/dto/RoleQueryCriteria.java | 36 + .../system/service/dto/RoleSmallDto.java | 35 + .../service/dto/UpdateGoogleAuthDTO.java | 27 + .../modules/system/service/dto/UserDto.java | 67 ++ .../system/service/dto/UserQueryCriteria.java | 49 + .../system/service/impl/DataServiceImpl.java | 91 ++ .../system/service/impl/DeptServiceImpl.java | 283 +++++ .../service/impl/DictDetailServiceImpl.java | 95 ++ .../system/service/impl/DictServiceImpl.java | 121 +++ .../system/service/impl/JobServiceImpl.java | 132 +++ .../system/service/impl/MenuServiceImpl.java | 355 +++++++ .../service/impl/MonitorServiceImpl.java | 187 ++++ .../system/service/impl/RoleServiceImpl.java | 226 ++++ .../system/service/impl/UserServiceImpl.java | 282 +++++ .../service/impl/VerifyServiceImpl.java | 81 ++ .../system/service/mapstruct/DeptMapper.java | 30 + .../service/mapstruct/DeptSmallMapper.java | 31 + .../service/mapstruct/DictDetailMapper.java | 31 + .../system/service/mapstruct/DictMapper.java | 31 + .../service/mapstruct/DictSmallMapper.java | 31 + .../system/service/mapstruct/JobMapper.java | 30 + .../service/mapstruct/JobSmallMapper.java | 31 + .../system/service/mapstruct/MenuMapper.java | 30 + .../system/service/mapstruct/RoleMapper.java | 31 + .../service/mapstruct/RoleSmallMapper.java | 31 + .../system/service/mapstruct/UserMapper.java | 30 + .../utils/GoogleAuthenticatorUtil.java | 179 ++++ wjcy-system/src/main/resources/banner.txt | 8 + .../main/resources/config/application-dev.yml | 285 +++++ .../resources/config/application-local.yml | 411 ++++++++ .../resources/config/application-prod.yml | 250 +++++ .../main/resources/config/application-xxs.yml | 417 ++++++++ .../src/main/resources/config/application.yml | 56 + .../src/main/resources/generator.properties | 27 + .../src/main/resources/ip2region/ip2region.db | Bin 0 -> 6502265 bytes wjcy-system/src/main/resources/log4j2.xml | 252 +++++ .../main/resources/log4jdbc.log4j2.properties | 5 + .../main/resources/template/email/email.ftl | 48 + .../resources/template/email/taskAlarm.ftl | 69 ++ .../template/generator/admin/Controller.ftl | 87 ++ .../template/generator/admin/Dto.ftl | 54 + .../template/generator/admin/Entity.ftl | 85 ++ .../template/generator/admin/Mapper.ftl | 32 + .../generator/admin/QueryCriteria.ftl | 81 ++ .../template/generator/admin/Repository.ftl | 40 + .../template/generator/admin/Service.ftl | 83 ++ .../template/generator/admin/ServiceImpl.ftl | 157 +++ .../template/generator/front/api.ftl | 27 + .../template/generator/front/index.ftl | 169 +++ .../src/main/resources/templates/index.html | 244 +++++ .../me/zhengjie/CtBuyerControllerTest.java | 127 +++ .../me/zhengjie/CtPlatformControllerTest.java | 43 + .../src/test/java/me/zhengjie/DhApiTest.java | 461 ++++++++ .../test/java/me/zhengjie/ExcelUserTest.java | 21 + .../me/zhengjie/SettingSiteServiceTest.java | 48 + .../java/me/zhengjie/TransactionSignDemo.java | 8 + wjcy-tools/pom.xml | 57 + .../me/zhengjie/config/MultipartConfig.java | 47 + .../java/me/zhengjie/domain/AlipayConfig.java | 76 ++ .../java/me/zhengjie/domain/EmailConfig.java | 58 + .../java/me/zhengjie/domain/LocalStorage.java | 73 ++ .../java/me/zhengjie/domain/QiniuConfig.java | 69 ++ .../java/me/zhengjie/domain/QiniuContent.java | 64 ++ .../java/me/zhengjie/domain/vo/EmailVo.java | 44 + .../java/me/zhengjie/domain/vo/TradeVo.java | 63 ++ .../zhengjie/repository/AliPayRepository.java | 26 + .../zhengjie/repository/EmailRepository.java | 26 + .../repository/LocalStorageRepository.java | 27 + .../repository/QiNiuConfigRepository.java | 36 + .../repository/QiniuContentRepository.java | 34 + .../me/zhengjie/rest/AliPayController.java | 135 +++ .../me/zhengjie/rest/EmailController.java | 63 ++ .../zhengjie/rest/LocalStorageController.java | 98 ++ .../me/zhengjie/rest/QiniuController.java | 122 +++ .../me/zhengjie/service/AliPayService.java | 57 + .../me/zhengjie/service/EmailService.java | 49 + .../zhengjie/service/LocalStorageService.java | 82 ++ .../me/zhengjie/service/QiNiuService.java | 118 +++ .../zhengjie/service/dto/LocalStorageDto.java | 42 + .../dto/LocalStorageQueryCriteria.java | 36 + .../service/dto/PictureQueryCriteria.java | 40 + .../service/dto/QiniuQueryCriteria.java | 36 + .../service/impl/AliPayServiceImpl.java | 119 +++ .../service/impl/EmailServiceImpl.java | 105 ++ .../service/impl/LocalStorageServiceImpl.java | 133 +++ .../service/impl/QiNiuServiceImpl.java | 237 +++++ .../service/mapstruct/LocalStorageMapper.java | 31 + .../me/zhengjie/utils/AliPayStatusEnum.java | 46 + .../java/me/zhengjie/utils/AlipayUtils.java | 85 ++ .../java/me/zhengjie/utils/QiNiuUtil.java | 71 ++ .../java/me/zhengjie/utils/RSACoderUtil.java | 234 +++++ 716 files changed, 56963 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 pom.xml create mode 100644 wjcy-common/pom.xml create mode 100644 wjcy-common/src/main/java/me/zhengjie/annotation/AnonymousAccess.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/annotation/CheckPwd.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/annotation/DataPermission.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/annotation/DateTime.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/annotation/FormSubmission.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/annotation/Limit.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/annotation/Query.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousDeleteMapping.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousGetMapping.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPatchMapping.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPostMapping.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPutMapping.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/aspect/LimitAspect.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/aspect/LimitType.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/base/BaseDTO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/base/BaseEntity.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/base/BaseMapper.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/AuditorConfig.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/BeanFactory.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/CorsInterceptor.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/CustomIdGenerator.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/DhApiProperties.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/ElPermissionConfig.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/FileProperties.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/MvcConfig.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/MyMetaObjectHandler.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/MybatisPlusConfig.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/PlatsProperties.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/PropertiesConfig.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/RedisConfig.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/RedissonConfig.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/RsaProperties.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/SwaggerConfig.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/SystemConfig.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/YdApiProperties.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/config/constant/Constants.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/constant/Constants.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/constant/PublicConstant.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/CtApplyDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/CtBrowseDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/CtBuyerDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/CtCardDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/CtClickFarmingDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/CtClickOrderDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/CtCompanyDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/CtDhPayDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/CtExcelDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/CtExcelImportInfoDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/CtOrderDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/CtPlatformDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/CtRebotDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/CtResponseOrderAddressDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/CtResponseOrderDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/CtResponseOrderProductDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/CtVpnDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/DhAddCarDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/DhAddCarOrderDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/DhCarGoodsDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/LoginIpDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/SettingSiteDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/SysQuartzJobDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/SysQuartzLogDao.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dao/mapper/CtDhPayService.xml create mode 100644 wjcy-common/src/main/java/me/zhengjie/dto/Dto.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dto/PageDTO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/dto/StatementAggregateDTO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtApply.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtBrowse.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtBrowseYdParams.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtBuyer.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerClickSuccess.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerContactInfo.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerExport.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerExportTemple.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerImport.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtCard.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtCardExport.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtCardExportTemple.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtCardImport.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtCardInfo.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmSupplyMentYdParams.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmYdParams.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarming.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmingExport.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmingExportTemp.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmingImport.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmingOrderInfo.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrder.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrderExport.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrderExportTemple.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrderImport.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrderYdParams.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtCompany.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtCompanyInfo.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtDhPay.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtDhPayExport.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtDhPayExportTemple.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtDhPayImport.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtExcel.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtExcelExportInfo.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtExcelExportTemple.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtExcelImportInfo.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtOrder.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtParamContactInfo.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtParamProduct.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtPlatform.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtRebot.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtRebotExport.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtRebotExportTemple.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtRebotImport.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtResponseOrder.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtResponseOrderAddress.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtResponseOrderProduct.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtSettingSite.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtVpn.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtVpnExport.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtVpnExportTemple.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtVpnImport.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/CtVpnInfo.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/DhAddCar.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/DhAddCarOrder.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/DhCarGoods.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/ExcelImportInfo.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/LoginIp.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/QueryWrapperAndPage.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/ResultObj.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/ReturnObje.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/SysQuartzJob.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/SysQuartzLog.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/YdSign.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/YdStartReturn.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/quartz/Boss.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/quartz/DataInfo.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryByUuid.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryByUuidData.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryByUuidReturn.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryByUuidRobotParams.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryReturnResult.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/quartz/Param.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/quartz/Params.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/quartz/RebotStatu.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/quartz/RebotStatuInfo.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/quartz/RebotStatuReturn.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/quartz/SecreInfo.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/entity/quartz/StartYdReturnInfo.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/BuyerLevelEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/BuyerOccupyStatusEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/BuyerStatusEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/CardDealerTypeEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/CardStatusEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/CardTypeEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/ClickBrowseStatusEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/ClickFarmingStatusEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/ClickOrderStatusEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/CtReboteStatusEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/DhAddCarStatusEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/DhPayStatusEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/ExcelInfoRequestTypeEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/ExcelStatusEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/LanguageEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/OrderTypeEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/ParamsTypeEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/PlatTypeEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/RobotStatusEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/TaskInfoEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/TaskIsPauseEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/TaskTypeEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/VpnDealerEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/VpnStatusEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/VpnTypeEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/YesOrNoEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/interfaces/IntegerEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/interfaces/LongEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/enums/interfaces/MemberIsUsedEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/error/ErrorCodeEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/exception/BadConfigurationException.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/exception/BadRequestException.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/exception/EntityExistException.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/exception/EntityNotFoundException.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/exception/handler/ApiError.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/exception/handler/GlobalExceptionHandler.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/mybatis/LambdaQueryWrapperImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/CtApplyService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/CtBrowseService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/CtBuyerService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/CtCardService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/CtClickFarmingService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/CtClickOrderService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/CtCompanyService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/CtDhPayService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/CtExcelImportInfoService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/CtExcelService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/CtOrderService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/CtPlatformService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/CtRebotService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/CtResponseOrderAddressService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/CtResponseOrderProductService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/CtResponseOrderService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/CtVpnService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/DhAddCarOrderService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/DhAddCarService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/DhCarGoodsService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/FileUploadService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/LoginIpService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/SettingSiteService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/SysQuartzLogService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/YdQuartzService.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/CtApplyServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/CtBrowseServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/CtBuyerServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/CtCardServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/CtClickFarmingServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/CtClickOrderServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/CtCompanyServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/CtDhPayServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/CtExcelImportInfoServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/CtExcelServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/CtOrderServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/CtPlatformServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/CtRebotServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/CtResponseOrderAddressServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/CtResponseOrderProductServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/CtResponseOrderServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/CtVpnServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/DhAddCarOrderServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/DhAddCarServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/DhCarGoodsServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/FileUploadServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/LoginIpServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/SettingSiteServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/SysQuartzJobServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/SysQuartzLogServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/impl/YdQuartzServiceImpl.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/redission/LockCallBack.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/AdminGoogleAuthInfoVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/BuyOrderResponseAddressVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/BuyOrderResponseOrderVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/BuyOrderResponseProductVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/BuyOrderVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtApplyInfoVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtApplyListVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtBrowseDetailVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtBrowseListVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtBuyerClickFarmVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtBuyerDetailVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtBuyerListVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtBuyerVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtCardDetailVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtCardListVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickFarmEditDetailVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickFarmingDetailVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickFarmingVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickOrderDetailVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickOrderListVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtCompanyInfoVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtCompanyVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtDhPayDetailVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtDhPayListVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtExcelImportInfoVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtExcelVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtOrderVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtPlatformInfoVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtPlatformVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtRebotListVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtVpnInfoVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/CtVpnVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/GoogleAuthInfoVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/LoginIpVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/OrderResponStatusVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/OrderResponSubErrorVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/OrderResponseVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/PayOrderVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/SettingSiteVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/SysQuartzJobListVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/SysQuartzLogListVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/dhaddcar/DhAddCarListVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/dhaddcar/DhAddCarVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/dhaddcar/DhAddCarYdParamsVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/dhcargood/DhCarGoodKeyVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/dhcargood/DhCarGoodLinkVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/dhcarorder/DhAddCarOrderListVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/service/vo/dhcarorder/DhCarOrderParamsVO.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/CacheKey.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/CallBack.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/CheckPwdValidator.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/CloseUtil.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/CronUtils.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/DateTimeValidator.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/DateUtil.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/ElAdminConstant.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/EmptyAttributeFiler.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/EncryptUtils.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/FileUtil.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/HexUtil.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/HttpClientUtil.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/HttpConnectionManager.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/JsonDealUtils.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/LoginIpUtil.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/MD5Util.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/OrderGetIndexUtil.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/PageUtil.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/PageUtils.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/PopularizeUtil.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/PropertiesUtil.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/QueryHelp.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/RedisUtils.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/RedissonUtil.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/RequestHolder.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/RsaUtils.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/SecurityUtils.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/SpringContextHolder.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/StringUtil.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/StringUtils.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/ThrowableUtil.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/TransformMap.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/TransformQueryWrapper.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/TranslatorUtil.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/ValidationUtil.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/YdCallBackUtil.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/YdParamsCheck.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/YdSignUtil.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/enums/CodeBiEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/enums/CodeEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/enums/DataScopeEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/enums/RequestMethodEnum.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/excel/ExcelClassField.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/excel/ExcelExport.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/excel/ExcelImport.java create mode 100644 wjcy-common/src/main/java/me/zhengjie/utils/excel/ExcelUtils.java create mode 100644 wjcy-common/src/test/java/me/zhengjie/utils/EncryptUtilsTest.java create mode 100644 wjcy-common/src/test/java/me/zhengjie/utils/FileUtilTest.java create mode 100644 wjcy-common/src/test/java/me/zhengjie/utils/StringUtilsTest.java create mode 100644 wjcy-generator/pom.xml create mode 100644 wjcy-generator/src/main/java/me/zhengjie/domain/ColumnInfo.java create mode 100644 wjcy-generator/src/main/java/me/zhengjie/domain/GenConfig.java create mode 100644 wjcy-generator/src/main/java/me/zhengjie/domain/vo/TableInfo.java create mode 100644 wjcy-generator/src/main/java/me/zhengjie/repository/ColumnInfoRepository.java create mode 100644 wjcy-generator/src/main/java/me/zhengjie/repository/GenConfigRepository.java create mode 100644 wjcy-generator/src/main/java/me/zhengjie/rest/GenConfigController.java create mode 100644 wjcy-generator/src/main/java/me/zhengjie/rest/GeneratorController.java create mode 100644 wjcy-generator/src/main/java/me/zhengjie/service/GenConfigService.java create mode 100644 wjcy-generator/src/main/java/me/zhengjie/service/GeneratorService.java create mode 100644 wjcy-generator/src/main/java/me/zhengjie/service/impl/GenConfigServiceImpl.java create mode 100644 wjcy-generator/src/main/java/me/zhengjie/service/impl/GeneratorServiceImpl.java create mode 100644 wjcy-generator/src/main/java/me/zhengjie/utils/ColUtil.java create mode 100644 wjcy-generator/src/main/java/me/zhengjie/utils/GenUtil.java create mode 100644 wjcy-logging/pom.xml create mode 100644 wjcy-logging/src/main/java/me/zhengjie/annotation/Log.java create mode 100644 wjcy-logging/src/main/java/me/zhengjie/annotation/type/LogActionType.java create mode 100644 wjcy-logging/src/main/java/me/zhengjie/annotation/type/LogDaoType.java create mode 100644 wjcy-logging/src/main/java/me/zhengjie/annotation/type/LogGetIdType.java create mode 100644 wjcy-logging/src/main/java/me/zhengjie/annotation/type/LogGetValueType.java create mode 100644 wjcy-logging/src/main/java/me/zhengjie/aspect/LogAspect.java create mode 100644 wjcy-logging/src/main/java/me/zhengjie/domain/Log.java create mode 100644 wjcy-logging/src/main/java/me/zhengjie/enums/LogTypeEnum.java create mode 100644 wjcy-logging/src/main/java/me/zhengjie/repository/LogRepository.java create mode 100644 wjcy-logging/src/main/java/me/zhengjie/rest/LogController.java create mode 100644 wjcy-logging/src/main/java/me/zhengjie/service/LogService.java create mode 100644 wjcy-logging/src/main/java/me/zhengjie/service/dto/LogErrorDTO.java create mode 100644 wjcy-logging/src/main/java/me/zhengjie/service/dto/LogQueryCriteria.java create mode 100644 wjcy-logging/src/main/java/me/zhengjie/service/dto/LogSmallDTO.java create mode 100644 wjcy-logging/src/main/java/me/zhengjie/service/impl/LogServiceImpl.java create mode 100644 wjcy-logging/src/main/java/me/zhengjie/service/mapstruct/LogErrorMapper.java create mode 100644 wjcy-logging/src/main/java/me/zhengjie/service/mapstruct/LogSmallMapper.java create mode 100644 wjcy-system/pom.xml create mode 100644 wjcy-system/src/main/java/me/zhengjie/AppRun.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/aspect/FormSubmissionAspect.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/config/ConfigurerAdapter.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/config/CorsConfig.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/config/GoogleAuthProperties.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/config/WebSocketConfig.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/config/thread/AsyncTaskExecutePool.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/config/thread/AsyncTaskProperties.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/config/thread/TheadFactoryName.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/config/thread/ThreadPoolExecutorUtil.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/aspect/LogAspect.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/capital/controller/FileUploadController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/capital/controller/GoogleAuthController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/capital/controller/LoginIpController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/capital/controller/SettingSiteController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/AddLoginIpDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/EditLoginIpDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/IdDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/RelSettingSiteDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/SettingSiteDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtApplyController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtBrowseController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtBuyerController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtCardController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtClickFarmingController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtClickOrderController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtCompanyController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtDhPayController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtExcelController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtExcelInfoController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtOrderController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtPlatformController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtRebotController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtVpnController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/DhAddCarCatchController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/DhAddCarController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/DhAddCarOrderController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/QuartzLogController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/SdsController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/SysQuartzJobController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/YdCallBackController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/BossTaskCallBackController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/ClickFarmingCallBackController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/ClickFarmingSuppleMentCallBackController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/ClickOrderCallBackController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/CtbrowseCallBackController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/DhAddCarCallBackController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/DhCarOrderCallBackController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/DhCatchOrderCallBackController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtApplyAddDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtApplyListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtApplyUpdateDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBrowseAddDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBrowseListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBrowseUpdateDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBuyerAddDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBuyerListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBuyerUpdateDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCardAddDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCardListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCardUpdateDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickFarmingAddDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickFarmingDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickFarmingEditDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickOrderAddDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickOrderCommentDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickOrderListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickOrderSupplementDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCompanyAddDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCompanyListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCompanyUpdateDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtDhPayAddDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtDhPayListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtExcelAddDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtExcelImportInfoListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtExcelListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtExcelUpdateDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtOrderListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtPlatformAddDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtPlatformListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtPlatformUpdateDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtRebotAddDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtRebotListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtRebotUpdateDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtRebotUpdateStatusDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtVpnAddDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtVpnListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtVpnUpdateDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/DhCarGoodWellReceivedDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/DhCarWellReceivedDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/IdDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SearchOrderListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SysQuartzJobAddDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SysQuartzJobListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SysQuartzJobUpdateDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SysQuartzLogListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhaddcar/DhAddCarAddDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhaddcar/DhAddCarEditDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhaddcar/DhAddCarListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcargood/DhCarGoodKeyAddDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcargood/DhCarGoodKeyEditDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcargood/DhCarGoodLinkAddDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcargood/DhCarGoodLinkEditDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcarorder/DhAddCarOrderListDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/App.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/Database.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/Deploy.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/DeployHistory.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/ServerDeploy.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/AppRepository.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/DatabaseRepository.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/DeployHistoryRepository.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/DeployRepository.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/ServerDeployRepository.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/AppController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/DatabaseController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/DeployController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/DeployHistoryController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/ServerDeployController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/AppService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/DatabaseService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/DeployHistoryService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/DeployService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/ServerDeployService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/AppDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/AppQueryCriteria.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DatabaseDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DatabaseQueryCriteria.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DeployDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DeployHistoryDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DeployHistoryQueryCriteria.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DeployQueryCriteria.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/ServerDeployDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/ServerDeployQueryCriteria.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/AppServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/DatabaseServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/DeployHistoryServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/DeployServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/ServerDeployServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/AppMapper.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/DatabaseMapper.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/DeployHistoryMapper.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/DeployMapper.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/ServerDeployMapper.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/util/DataTypeEnum.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/util/ExecuteShellUtil.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/util/ScpClientUtil.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/util/SqlUtils.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/websocket/MsgType.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/websocket/SocketMsg.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/mnt/websocket/WebSocketServer.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/config/JobRunner.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/config/QuartzConfig.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/domain/QuartzJob.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/domain/QuartzLog.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/repository/QuartzJobRepository.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/repository/QuartzLogRepository.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/rest/QuartzJobController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/QuartzJobService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/SysQuartzJobService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/dto/JobQueryCriteria.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/impl/QuartzJobServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/impl/SysQuartzJobServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/BossTask.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/BossTask22.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/BrowseTask.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/ClickFarmSuppleMentTask.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/ClickFarmTask.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/DhAddCarTask.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/DhCatchOrderTask.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/DhPayTask.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/DhWellReceivedTask.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/ExcelToOrderTask.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/ExcelmportTask.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/OrderToPayTask.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/RebotStatusTask.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/TestTask.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/WellReceivedTask.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/utils/ExecutionJob.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/utils/QuartzManage.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/utils/QuartzRunnable.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/quartz/utils/YdApiUtil.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/config/ConfigBeanConfiguration.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/config/SecurityConfig.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/config/bean/LoginCode.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/config/bean/LoginCodeEnum.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/config/bean/LoginProperties.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/config/bean/SecurityProperties.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/rest/AuthorizationController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/rest/OnlineController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/security/JwtAccessDeniedHandler.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/security/JwtAuthenticationEntryPoint.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/security/TokenConfigurer.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/security/TokenFilter.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/security/TokenProvider.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/service/OnlineUserService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/service/UserCacheClean.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/service/UserDetailsServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/service/dto/AuthUserDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/service/dto/JwtUserDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/security/service/dto/OnlineUserDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Dept.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Dict.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/domain/DictDetail.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Job.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Menu.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Role.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/domain/User.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/domain/vo/MenuMetaVo.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/domain/vo/MenuVo.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/domain/vo/UserPassVo.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/repository/DeptRepository.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/repository/DictDetailRepository.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/repository/DictRepository.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/repository/JobRepository.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/repository/MenuRepository.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/repository/RoleRepository.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/repository/UserRepository.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/rest/DeptController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/rest/DictController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/rest/DictDetailController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/rest/JobController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/rest/LimitController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/rest/MenuController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/rest/MonitorController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/rest/RoleController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/rest/UserController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/rest/VerifyController.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/DataService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/DeptService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/DictDetailService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/DictService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/JobService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/MenuService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/MonitorService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/RoleService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/UserService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/VerifyService.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DeptDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DeptQueryCriteria.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DeptSmallDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictDetailDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictDetailQueryCriteria.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictQueryCriteria.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictSmallDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/GoogleAuthCodeDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/GoogleAuthGenSecretDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/GoogleAuthQrBarCodeUrlDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/JobDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/JobQueryCriteria.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/JobSmallDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/MenuDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/MenuQueryCriteria.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/RoleDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/RoleQueryCriteria.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/RoleSmallDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/UpdateGoogleAuthDTO.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/UserDto.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/UserQueryCriteria.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/DataServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/DeptServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/DictDetailServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/DictServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/JobServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/MenuServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/MonitorServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/RoleServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/UserServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/VerifyServiceImpl.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DeptMapper.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DeptSmallMapper.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DictDetailMapper.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DictMapper.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DictSmallMapper.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/JobMapper.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/JobSmallMapper.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/MenuMapper.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/RoleMapper.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/RoleSmallMapper.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/UserMapper.java create mode 100644 wjcy-system/src/main/java/me/zhengjie/modules/utils/GoogleAuthenticatorUtil.java create mode 100644 wjcy-system/src/main/resources/banner.txt create mode 100644 wjcy-system/src/main/resources/config/application-dev.yml create mode 100644 wjcy-system/src/main/resources/config/application-local.yml create mode 100644 wjcy-system/src/main/resources/config/application-prod.yml create mode 100644 wjcy-system/src/main/resources/config/application-xxs.yml create mode 100644 wjcy-system/src/main/resources/config/application.yml create mode 100644 wjcy-system/src/main/resources/generator.properties create mode 100644 wjcy-system/src/main/resources/ip2region/ip2region.db create mode 100644 wjcy-system/src/main/resources/log4j2.xml create mode 100644 wjcy-system/src/main/resources/log4jdbc.log4j2.properties create mode 100644 wjcy-system/src/main/resources/template/email/email.ftl create mode 100644 wjcy-system/src/main/resources/template/email/taskAlarm.ftl create mode 100644 wjcy-system/src/main/resources/template/generator/admin/Controller.ftl create mode 100644 wjcy-system/src/main/resources/template/generator/admin/Dto.ftl create mode 100644 wjcy-system/src/main/resources/template/generator/admin/Entity.ftl create mode 100644 wjcy-system/src/main/resources/template/generator/admin/Mapper.ftl create mode 100644 wjcy-system/src/main/resources/template/generator/admin/QueryCriteria.ftl create mode 100644 wjcy-system/src/main/resources/template/generator/admin/Repository.ftl create mode 100644 wjcy-system/src/main/resources/template/generator/admin/Service.ftl create mode 100644 wjcy-system/src/main/resources/template/generator/admin/ServiceImpl.ftl create mode 100644 wjcy-system/src/main/resources/template/generator/front/api.ftl create mode 100644 wjcy-system/src/main/resources/template/generator/front/index.ftl create mode 100644 wjcy-system/src/main/resources/templates/index.html create mode 100644 wjcy-system/src/test/java/me/zhengjie/CtBuyerControllerTest.java create mode 100644 wjcy-system/src/test/java/me/zhengjie/CtPlatformControllerTest.java create mode 100644 wjcy-system/src/test/java/me/zhengjie/DhApiTest.java create mode 100644 wjcy-system/src/test/java/me/zhengjie/ExcelUserTest.java create mode 100644 wjcy-system/src/test/java/me/zhengjie/SettingSiteServiceTest.java create mode 100644 wjcy-system/src/test/java/me/zhengjie/TransactionSignDemo.java create mode 100644 wjcy-tools/pom.xml create mode 100644 wjcy-tools/src/main/java/me/zhengjie/config/MultipartConfig.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/domain/AlipayConfig.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/domain/EmailConfig.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/domain/LocalStorage.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/domain/QiniuConfig.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/domain/QiniuContent.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/domain/vo/EmailVo.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/domain/vo/TradeVo.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/repository/AliPayRepository.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/repository/EmailRepository.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/repository/LocalStorageRepository.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/repository/QiNiuConfigRepository.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/repository/QiniuContentRepository.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/rest/AliPayController.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/rest/EmailController.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/rest/LocalStorageController.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/rest/QiniuController.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/service/AliPayService.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/service/EmailService.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/service/LocalStorageService.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/service/QiNiuService.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/service/dto/LocalStorageDto.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/service/dto/LocalStorageQueryCriteria.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/service/dto/PictureQueryCriteria.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/service/dto/QiniuQueryCriteria.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/service/impl/AliPayServiceImpl.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/service/impl/EmailServiceImpl.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/service/impl/LocalStorageServiceImpl.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/service/impl/QiNiuServiceImpl.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/service/mapstruct/LocalStorageMapper.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/utils/AliPayStatusEnum.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/utils/AlipayUtils.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/utils/QiNiuUtil.java create mode 100644 wjcy-tools/src/main/java/me/zhengjie/utils/RSACoderUtil.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ca38718 --- /dev/null +++ b/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "{}" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright 2019-2020 Zheng Jie + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..484acf5 --- /dev/null +++ b/README.md @@ -0,0 +1,83 @@ +

EL-ADMIN 后台管理系统

+
+#### 项目简介 +一个基于 Spring Boot 2.1.0 、 Spring Boot Jpa、 JWT、Spring Security、Redis、Vue的前后端分离的后台管理系统 + +**开发文档:** [https://el-admin.vip](https://el-admin.vip) + +**体验地址:** [https://el-admin.xin](https://el-admin.xin) + +**账号密码:** `admin / 123456` + +#### 项目源码 + +| | 后端源码 | 前端源码 | +|--- |--- | --- | +| github | https://github.com/elunez/eladmin | https://github.com/elunez/eladmin-web | +| 码云 | https://gitee.com/elunez/eladmin | https://gitee.com/elunez/eladmin-web | + +#### 主要特性 +- 使用最新技术栈,社区资源丰富。 +- 高效率开发,代码生成器可一键生成前后端代码 +- 支持数据字典,可方便地对一些状态进行管理 +- 支持接口限流,避免恶意请求导致服务层压力过大 +- 支持接口级别的功能权限与数据权限,可自定义操作 +- 自定义权限注解与匿名接口注解,可快速对接口拦截与放行 +- 对一些常用地前端组件封装:表格数据请求、数据字典等 +- 前后端统一异常拦截处理,统一输出异常,避免繁琐的判断 +- 支持在线用户管理与服务器性能监控,支持限制单用户登录 +- 支持运维管理,可方便地对远程服务器的应用进行部署与管理 + +#### 系统功能 +- 用户管理:提供用户的相关配置,新增用户后,默认密码为123456 +- 角色管理:对权限与菜单进行分配,可根据部门设置角色的数据权限 +- 菜单管理:已实现菜单动态路由,后端可配置化,支持多级菜单 +- 部门管理:可配置系统组织架构,树形表格展示 +- 岗位管理:配置各个部门的职位 +- 字典管理:可维护常用一些固定的数据,如:状态,性别等 +- 系统日志:记录用户操作日志与异常日志,方便开发人员定位排错 +- SQL监控:采用druid 监控数据库访问性能,默认用户名admin,密码123456 +- 定时任务:整合Quartz做定时任务,加入任务日志,任务运行情况一目了然 +- 代码生成:高灵活度生成前后端代码,减少大量重复的工作任务 +- 邮件工具:配合富文本,发送html格式的邮件 +- 七牛云存储:可同步七牛云存储的数据到系统,无需登录七牛云直接操作云数据 +- 支付宝支付:整合了支付宝支付并且提供了测试账号,可自行测试 +- 服务监控:监控服务器的负载情况 +- 运维管理:一键部署你的应用 + +#### 项目结构 +项目采用按功能分模块的开发方式,结构如下 + +- `capiltal-common` 为系统的公共模块,各种工具类,公共配置存在该模块 + +- `capiltal-client` 为客户端api模块,也是最终需要打包部署的模块 + +- `capiltal-system` 为系统核心模块也是项目入口模块,也是最终需要打包部署的模块 + +- `capiltal-logging` 为系统的日志模块,其他模块如果需要记录日志需要引入该模块 + +- `capiltal-tools` 为第三方工具模块,包含:图床、邮件、云存储、本地存储、支付宝 + +- `capiltal-generator` 为系统的代码生成模块,代码生成的模板在 system 模块中 + +#### 详细结构 + +``` +- capiltal-common 公共模块 + - annotation 为系统自定义注解 + - aspect 自定义注解的切面 + - base 提供了Entity、DTO基类和mapstruct的通用mapper + - config 自定义权限实现、redis配置、swagger配置、Rsa配置等 + - dao MybatiesPlus Dao + - mapper mybatiesPlus Mapper + - exception 项目统一异常的处理 + - utils 系统通用工具类 +- capiltal-system 系统核心模块(系统启动入口) + - config 配置跨域与静态资源,与数据权限 + - thread 线程池相关 + - modules 系统相关模块(登录授权、系统监控、定时任务、运维管理等) +- capiltal-logging 系统日志模块 +- capiltal-tools 系统第三方工具模块 +- capiltal-generator 系统代码生成模块 +``` + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..313c8bc --- /dev/null +++ b/pom.xml @@ -0,0 +1,321 @@ + + + 4.0.0 + + me.zhengjie + wjcy + pom + 1.0 + + + wjcy-common + wjcy-logging + wjcy-system + wjcy-tools + wjcy-generator + + + EL-ADMIN 后台管理 + http://auauz.net + + + org.springframework.boot + spring-boot-starter-parent + 2.2.10.RELEASE + + + + UTF-8 + UTF-8 + 1.8 + 1.16 + 1.2.70 + 1.1.24 + 2.5.0 + 1.3.1.Final + 2.1.1 + 2.15.0 + 2.0.7 + + + + + + org.springframework.boot + spring-boot-starter-logging + + + * + * + + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.springframework.boot + spring-boot-starter-security + + + + + org.springframework.boot + spring-boot-starter-cache + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + org.apache.commons + commons-pool2 + ${commons-pool2.version} + + + org.apache.commons + commons-lang3 + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.bgee.log4jdbc-log4j2 + log4jdbc-log4j2-jdbc4.1 + ${log4jdbc.version} + + + + + com.github.xiaoymin + knife4j-spring-boot-starter + ${knife4j.version} + + + + + mysql + mysql-connector-java + runtime + + + + + com.alibaba + druid-spring-boot-starter + ${druid.version} + + + org.lionsoul + ip2region + 1.7.2 + + + + + org.projectlombok + lombok + true + + + + + + + com.alibaba + fastjson + ${fastjson.version} + + + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + provided + + + javax.inject + javax.inject + 1 + + + + + com.github.whvcse + easy-captcha + 1.6.2 + + + + + nl.basjes.parse.useragent + yauaa + 5.23 + + + + + com.baomidou + mybatis-plus-boot-starter + 3.3.2 + + + com.h2database + h2 + runtime + + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + + + org.apache.poi + poi + 4.0.1 + + + + + org.apache.poi + poi-ooxml + 4.0.1 + + + + net.sourceforge.jexcelapi + jxl + 2.6.10 + + + + org.redisson + redisson + 3.5.7 + + + + + org.apache.rocketmq + rocketmq-client + 4.4.0 + + + + + com.google.guava + guava + 24.1-jre + + + com.madgag.spongycastle + core + 1.58.0.0 + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.springframework.cloud + spring-cloud-starter-openfeign + 2.2.5.RELEASE + + + com.netflix.feign + feign-jackson + 8.18.0 + + + + org.telegram + telegrambots + 5.5.0 + + + + + + + + src/main/java + + **/*.xml + + true + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + + + + + public + aliyun nexus + http://maven.aliyun.com/nexus/content/groups/public/ + + true + + + + + + + public + aliyun nexus + http://maven.aliyun.com/nexus/content/groups/public/ + + true + + + false + + + + \ No newline at end of file diff --git a/wjcy-common/pom.xml b/wjcy-common/pom.xml new file mode 100644 index 0000000..12e75a5 --- /dev/null +++ b/wjcy-common/pom.xml @@ -0,0 +1,37 @@ + + + + wjcy + me.zhengjie + 1.0 + + 4.0.0 + + 5.3.4 + + + wjcy-common + 公共模块 + + + + + cn.hutool + hutool-all + ${hutool.version} + + + + org.apache.httpcomponents + httpclient + 4.5.12 + + + org.jodd + jodd-core + 3.7.1 + + + diff --git a/wjcy-common/src/main/java/me/zhengjie/annotation/AnonymousAccess.java b/wjcy-common/src/main/java/me/zhengjie/annotation/AnonymousAccess.java new file mode 100644 index 0000000..b2c168f --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/annotation/AnonymousAccess.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.annotation; + +import java.lang.annotation.*; + +/** + * @author jacky + * 用于标记匿名访问方法 + */ +@Inherited +@Documented +@Target({ElementType.METHOD,ElementType.ANNOTATION_TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface AnonymousAccess { + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/annotation/CheckPwd.java b/wjcy-common/src/main/java/me/zhengjie/annotation/CheckPwd.java new file mode 100644 index 0000000..459425b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/annotation/CheckPwd.java @@ -0,0 +1,25 @@ +package me.zhengjie.annotation; + +import me.zhengjie.utils.CheckPwdValidator; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.*; + +/* + * + * @Description 密码校验 + * @Date 2022/3/21 + * @Author zeng + */ +@Target({ElementType.FIELD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = CheckPwdValidator.class) +public @interface CheckPwd { + + String message() default "密码格式错误,必须包含大小写字母、数子、英文特殊符号,且长度在16~64之间!"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/annotation/DataPermission.java b/wjcy-common/src/main/java/me/zhengjie/annotation/DataPermission.java new file mode 100644 index 0000000..b73c1a2 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/annotation/DataPermission.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + *

+ * 用于判断是否过滤数据权限 + * 1、如果没有用到 @OneToOne 这种关联关系,只需要填写 fieldName [参考:DeptQueryCriteria.class] + * 2、如果用到了 @OneToOne ,fieldName 和 joinName 都需要填写,拿UserQueryCriteria.class举例: + * 应该是 @DataPermission(joinName = "dept", fieldName = "id") + *

+ * @author Zheng Jie + * @website https://el-admin.vip + * @date 2020-05-07 + **/ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface DataPermission { + + /** + * Entity 中的字段名称 + */ + String fieldName() default ""; + + /** + * Entity 中与部门关联的字段名称 + */ + String joinName() default ""; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/annotation/DateTime.java b/wjcy-common/src/main/java/me/zhengjie/annotation/DateTime.java new file mode 100644 index 0000000..385ddd9 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/annotation/DateTime.java @@ -0,0 +1,31 @@ +package me.zhengjie.annotation; + +import me.zhengjie.utils.DateTimeValidator; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +/** + *

+ * 日期格式效验 + *

+ * + * @Author xx + * @Date 2021/7/27 + **/ +@Target({ElementType.FIELD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = DateTimeValidator.class) +public @interface DateTime { + + String message() default "日期格式错误"; + + String format() default "yyyy-MM-dd HH:mm:ss"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/annotation/FormSubmission.java b/wjcy-common/src/main/java/me/zhengjie/annotation/FormSubmission.java new file mode 100644 index 0000000..d3e7f2d --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/annotation/FormSubmission.java @@ -0,0 +1,28 @@ +package me.zhengjie.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import static me.zhengjie.config.constant.Constants.FORM_SUB_SECOND; + +/** + *

+ * 表单提交 + *

+ * + * @author: rch + * @date: 2022-08-30 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface FormSubmission { + + /** 是否开启防止表单重复提交验证 */ + boolean isOpen() default true; + /** 表单重复提交时间间隔,单位;秒 */ + long second() default FORM_SUB_SECOND; + + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/annotation/Limit.java b/wjcy-common/src/main/java/me/zhengjie/annotation/Limit.java new file mode 100644 index 0000000..58b41cf --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/annotation/Limit.java @@ -0,0 +1,49 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.annotation; + +import me.zhengjie.aspect.LimitType; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author jacky + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Limit { + + // 资源名称,用于描述接口功能 + String name() default ""; + + // 资源 key + String key() default ""; + + // key prefix + String prefix() default ""; + + // 时间的,单位秒 + int period(); + + // 限制访问次数 + int count(); + + // 限制类型 + LimitType limitType() default LimitType.CUSTOMER; + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/annotation/Query.java b/wjcy-common/src/main/java/me/zhengjie/annotation/Query.java new file mode 100644 index 0000000..e1758c9 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/annotation/Query.java @@ -0,0 +1,90 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Zheng Jie + * @date 2019-6-4 13:52:30 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Query { + + // Dong ZhaoYang 2017/8/7 基本对象的属性名 + String propName() default ""; + // Dong ZhaoYang 2017/8/7 查询方式 + Type type() default Type.EQUAL; + + /** + * 连接查询的属性名,如User类中的dept + */ + String joinName() default ""; + + /** + * 默认左连接 + */ + Join join() default Join.LEFT; + + /** + * 多字段模糊搜索,仅支持String类型字段,多个用逗号隔开, 如@Query(blurry = "email,username") + */ + String blurry() default ""; + + enum Type { + // jie 2019/6/4 相等 + EQUAL + // Dong ZhaoYang 2017/8/7 大于等于 + , GREATER_THAN + // Dong ZhaoYang 2017/8/7 小于等于 + , LESS_THAN + // Dong ZhaoYang 2017/8/7 中模糊查询 + , INNER_LIKE + // Dong ZhaoYang 2017/8/7 左模糊查询 + , LEFT_LIKE + // Dong ZhaoYang 2017/8/7 右模糊查询 + , RIGHT_LIKE + // Dong ZhaoYang 2017/8/7 小于 + , LESS_THAN_NQ + // jie 2019/6/4 包含 + , IN + // 不包含 + , NOT_IN + // 不等于 + ,NOT_EQUAL + // between + ,BETWEEN + // 不为空 + ,NOT_NULL + // 为空 + ,IS_NULL + } + + /** + * @author Zheng Jie + * 适用于简单连接查询,复杂的请自定义该注解,或者使用sql查询 + */ + enum Join { + /** jie 2019-6-4 13:18:30 */ + LEFT, RIGHT, INNER + } + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousDeleteMapping.java b/wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousDeleteMapping.java new file mode 100644 index 0000000..6a81c2e --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousDeleteMapping.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zhengjie.annotation.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import me.zhengjie.annotation.AnonymousAccess; +import org.springframework.core.annotation.AliasFor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Annotation for mapping HTTP {@code DELETE} requests onto specific handler + * methods. + * 支持匿名访问 DeleteMapping + * + * @author liaojinlong + * @see AnonymousGetMapping + * @see AnonymousPostMapping + * @see AnonymousPutMapping + * @see AnonymousPatchMapping + * @see RequestMapping + */ +@AnonymousAccess +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@RequestMapping(method = RequestMethod.DELETE) +public @interface AnonymousDeleteMapping { + + /** + * Alias for {@link RequestMapping#name}. + */ + @AliasFor(annotation = RequestMapping.class) + String name() default ""; + + /** + * Alias for {@link RequestMapping#value}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] value() default {}; + + /** + * Alias for {@link RequestMapping#path}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] path() default {}; + + /** + * Alias for {@link RequestMapping#params}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] params() default {}; + + /** + * Alias for {@link RequestMapping#headers}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] headers() default {}; + + /** + * Alias for {@link RequestMapping#consumes}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] consumes() default {}; + + /** + * Alias for {@link RequestMapping#produces}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] produces() default {}; + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousGetMapping.java b/wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousGetMapping.java new file mode 100644 index 0000000..c260a71 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousGetMapping.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zhengjie.annotation.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import me.zhengjie.annotation.AnonymousAccess; +import org.springframework.core.annotation.AliasFor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Annotation for mapping HTTP {@code GET} requests onto specific handler + * methods. + *

+ * 支持匿名访问 GetMapping + * + * @author liaojinlong + * @see RequestMapping + */ +@AnonymousAccess +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@RequestMapping(method = RequestMethod.GET) +public @interface AnonymousGetMapping { + + /** + * Alias for {@link RequestMapping#name}. + */ + @AliasFor(annotation = RequestMapping.class) + String name() default ""; + + /** + * Alias for {@link RequestMapping#value}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] value() default {}; + + /** + * Alias for {@link RequestMapping#path}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] path() default {}; + + /** + * Alias for {@link RequestMapping#params}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] params() default {}; + + /** + * Alias for {@link RequestMapping#headers}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] headers() default {}; + + /** + * Alias for {@link RequestMapping#consumes}. + * + * @since 4.3.5 + */ + @AliasFor(annotation = RequestMapping.class) + String[] consumes() default {}; + + /** + * Alias for {@link RequestMapping#produces}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] produces() default {}; + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPatchMapping.java b/wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPatchMapping.java new file mode 100644 index 0000000..6686617 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPatchMapping.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zhengjie.annotation.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import me.zhengjie.annotation.AnonymousAccess; +import org.springframework.core.annotation.AliasFor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Annotation for mapping HTTP {@code PATCH} requests onto specific handler + * methods. + * * 支持匿名访问 PatchMapping + * + * @author liaojinlong + * @see AnonymousGetMapping + * @see AnonymousPostMapping + * @see AnonymousPutMapping + * @see AnonymousDeleteMapping + * @see RequestMapping + */ +@AnonymousAccess +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@RequestMapping(method = RequestMethod.PATCH) +public @interface AnonymousPatchMapping { + + /** + * Alias for {@link RequestMapping#name}. + */ + @AliasFor(annotation = RequestMapping.class) + String name() default ""; + + /** + * Alias for {@link RequestMapping#value}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] value() default {}; + + /** + * Alias for {@link RequestMapping#path}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] path() default {}; + + /** + * Alias for {@link RequestMapping#params}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] params() default {}; + + /** + * Alias for {@link RequestMapping#headers}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] headers() default {}; + + /** + * Alias for {@link RequestMapping#consumes}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] consumes() default {}; + + /** + * Alias for {@link RequestMapping#produces}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] produces() default {}; + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPostMapping.java b/wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPostMapping.java new file mode 100644 index 0000000..8f1cdcd --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPostMapping.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zhengjie.annotation.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import me.zhengjie.annotation.AnonymousAccess; +import org.springframework.core.annotation.AliasFor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Annotation for mapping HTTP {@code POST} requests onto specific handler + * methods. + * 支持匿名访问 PostMapping + * + * @author liaojinlong + * @see AnonymousGetMapping + * @see AnonymousPostMapping + * @see AnonymousPutMapping + * @see AnonymousDeleteMapping + * @see RequestMapping + */ +@AnonymousAccess +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@RequestMapping(method = RequestMethod.POST) +public @interface AnonymousPostMapping { + + /** + * Alias for {@link RequestMapping#name}. + */ + @AliasFor(annotation = RequestMapping.class) + String name() default ""; + + /** + * Alias for {@link RequestMapping#value}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] value() default {}; + + /** + * Alias for {@link RequestMapping#path}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] path() default {}; + + /** + * Alias for {@link RequestMapping#params}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] params() default {}; + + /** + * Alias for {@link RequestMapping#headers}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] headers() default {}; + + /** + * Alias for {@link RequestMapping#consumes}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] consumes() default {}; + + /** + * Alias for {@link RequestMapping#produces}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] produces() default {}; + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPutMapping.java b/wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPutMapping.java new file mode 100644 index 0000000..7c417da --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPutMapping.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zhengjie.annotation.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import me.zhengjie.annotation.AnonymousAccess; +import org.springframework.core.annotation.AliasFor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Annotation for mapping HTTP {@code PUT} requests onto specific handler + * methods. + * * 支持匿名访问 PutMapping + * + * @author liaojinlong + * @see AnonymousGetMapping + * @see AnonymousPostMapping + * @see AnonymousPutMapping + * @see AnonymousDeleteMapping + * @see RequestMapping + */ +@AnonymousAccess +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@RequestMapping(method = RequestMethod.PUT) +public @interface AnonymousPutMapping { + + /** + * Alias for {@link RequestMapping#name}. + */ + @AliasFor(annotation = RequestMapping.class) + String name() default ""; + + /** + * Alias for {@link RequestMapping#value}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] value() default {}; + + /** + * Alias for {@link RequestMapping#path}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] path() default {}; + + /** + * Alias for {@link RequestMapping#params}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] params() default {}; + + /** + * Alias for {@link RequestMapping#headers}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] headers() default {}; + + /** + * Alias for {@link RequestMapping#consumes}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] consumes() default {}; + + /** + * Alias for {@link RequestMapping#produces}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] produces() default {}; + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/aspect/LimitAspect.java b/wjcy-common/src/main/java/me/zhengjie/aspect/LimitAspect.java new file mode 100644 index 0000000..908e022 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/aspect/LimitAspect.java @@ -0,0 +1,99 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.aspect; + +import com.google.common.collect.ImmutableList; +import me.zhengjie.annotation.Limit; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.utils.RequestHolder; +import me.zhengjie.utils.StringUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.data.redis.core.script.RedisScript; +import org.springframework.stereotype.Component; +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; + +/** + * @author / + */ +@Aspect +@Component +public class LimitAspect { + + private final RedisTemplate redisTemplate; + private static final Logger logger = LoggerFactory.getLogger(LimitAspect.class); + + public LimitAspect(RedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + @Pointcut("@annotation(me.zhengjie.annotation.Limit)") + public void pointcut() { + } + + @Around("pointcut()") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + HttpServletRequest request = RequestHolder.getHttpServletRequest(); + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method signatureMethod = signature.getMethod(); + Limit limit = signatureMethod.getAnnotation(Limit.class); + LimitType limitType = limit.limitType(); + String key = limit.key(); + if (StringUtils.isEmpty(key)) { + if (limitType == LimitType.IP) { + key = StringUtils.getIp(request); + } else { + key = signatureMethod.getName(); + } + } + + ImmutableList keys = ImmutableList.of(StringUtils.join(limit.prefix(), "_", key, "_", request.getRequestURI().replaceAll("/","_"))); + + String luaScript = buildLuaScript(); + RedisScript redisScript = new DefaultRedisScript<>(luaScript, Number.class); + Number count = redisTemplate.execute(redisScript, keys, limit.count(), limit.period()); + if (null != count && count.intValue() <= limit.count()) { + logger.info("第{}次访问key为 {},描述为 [{}] 的接口", count, keys, limit.name()); + return joinPoint.proceed(); + } else { + throw new BadRequestException("访问次数受限制"); + } + } + + /** + * 限流脚本 + */ + private String buildLuaScript() { + return "local c" + + "\nc = redis.call('get',KEYS[1])" + + "\nif c and tonumber(c) > tonumber(ARGV[1]) then" + + "\nreturn c;" + + "\nend" + + "\nc = redis.call('incr',KEYS[1])" + + "\nif tonumber(c) == 1 then" + + "\nredis.call('expire',KEYS[1],ARGV[2])" + + "\nend" + + "\nreturn c;"; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/aspect/LimitType.java b/wjcy-common/src/main/java/me/zhengjie/aspect/LimitType.java new file mode 100644 index 0000000..bf3f09e --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/aspect/LimitType.java @@ -0,0 +1,27 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.aspect; + +/** + * 限流枚举 + * @author / + */ +public enum LimitType { + // 默认 + CUSTOMER, + // by ip addr + IP +} diff --git a/wjcy-common/src/main/java/me/zhengjie/base/BaseDTO.java b/wjcy-common/src/main/java/me/zhengjie/base/BaseDTO.java new file mode 100644 index 0000000..e9e7cc2 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/base/BaseDTO.java @@ -0,0 +1,40 @@ +package me.zhengjie.base; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.builder.ToStringBuilder; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.sql.Timestamp; + +/** + * @author Zheng Jie + * @date 2019年10月24日20:48:53 + */ +@Getter +@Setter +public class BaseDTO implements Serializable { + + private String createBy; + + private String updateBy; + + private Timestamp createTime; + + private Timestamp updateTime; + + @Override + public String toString() { + ToStringBuilder builder = new ToStringBuilder(this); + Field[] fields = this.getClass().getDeclaredFields(); + try { + for (Field f : fields) { + f.setAccessible(true); + builder.append(f.getName(), f.get(this)).append("\n"); + } + } catch (Exception e) { + builder.append("toString builder encounter an error"); + } + return builder.toString(); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/base/BaseEntity.java b/wjcy-common/src/main/java/me/zhengjie/base/BaseEntity.java new file mode 100644 index 0000000..618e100 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/base/BaseEntity.java @@ -0,0 +1,85 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.base; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; +import org.springframework.data.annotation.CreatedBy; +import org.springframework.data.annotation.LastModifiedBy; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; +import javax.persistence.Column; +import javax.persistence.EntityListeners; +import javax.persistence.MappedSuperclass; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.sql.Timestamp; + +/** + * 通用字段, is_del 根据需求自行添加 + * @author Zheng Jie + * @Date 2019年10月24日20:46:32 + */ +@Getter +@Setter +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +public class BaseEntity implements Serializable { + + @CreatedBy + @Column(name = "create_by", updatable = false) + @ApiModelProperty(value = "创建人", hidden = true) + private String createBy; + + @LastModifiedBy + @Column(name = "update_by") + @ApiModelProperty(value = "更新人", hidden = true) + private String updateBy; + + @CreationTimestamp + @Column(name = "create_time", updatable = false) + @ApiModelProperty(value = "创建时间", hidden = true) + private Timestamp createTime; + + @UpdateTimestamp + @Column(name = "update_time") + @ApiModelProperty(value = "更新时间", hidden = true) + private Timestamp updateTime; + + /* 分组校验 */ + public @interface Create {} + + /* 分组校验 */ + public @interface Update {} + + @Override + public String toString() { + ToStringBuilder builder = new ToStringBuilder(this); + Field[] fields = this.getClass().getDeclaredFields(); + try { + for (Field f : fields) { + f.setAccessible(true); + builder.append(f.getName(), f.get(this)).append("\n"); + } + } catch (Exception e) { + builder.append("toString builder encounter an error"); + } + return builder.toString(); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/base/BaseMapper.java b/wjcy-common/src/main/java/me/zhengjie/base/BaseMapper.java new file mode 100644 index 0000000..e8bb825 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/base/BaseMapper.java @@ -0,0 +1,53 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.base; + +import java.util.List; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +public interface BaseMapper { + + /** + * DTO转Entity + * @param dto / + * @return / + */ + E toEntity(D dto); + + /** + * Entity转DTO + * @param entity / + * @return / + */ + D toDto(E entity); + + /** + * DTO集合转Entity集合 + * @param dtoList / + * @return / + */ + List toEntity(List dtoList); + + /** + * Entity集合转DTO集合 + * @param entityList / + * @return / + */ + List toDto(List entityList); +} diff --git a/wjcy-common/src/main/java/me/zhengjie/config/AuditorConfig.java b/wjcy-common/src/main/java/me/zhengjie/config/AuditorConfig.java new file mode 100644 index 0000000..006ef6b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/AuditorConfig.java @@ -0,0 +1,45 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.config; + +import me.zhengjie.utils.SecurityUtils; +import org.springframework.data.domain.AuditorAware; +import org.springframework.stereotype.Component; +import java.util.Optional; + +/** + * @description : 设置审计 + * @author : Dong ZhaoYang + * @date : 2019/10/28 + */ +@Component("auditorAware") +public class AuditorConfig implements AuditorAware { + + /** + * 返回操作员标志信息 + * + * @return / + */ + @Override + public Optional getCurrentAuditor() { + try { + // 这里应根据实际业务情况获取具体信息 + return Optional.of(SecurityUtils.getCurrentUsername()); + }catch (Exception ignored){} + // 用户定时任务,或者无Token调用的情况 + return Optional.of("System"); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/config/BeanFactory.java b/wjcy-common/src/main/java/me/zhengjie/config/BeanFactory.java new file mode 100644 index 0000000..a293074 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/BeanFactory.java @@ -0,0 +1,105 @@ +package me.zhengjie.config; + + +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +/** + *

+ * bean 工厂, 通过spring容器获取容器中定义的bean + *

+ * + * @Author xx + * @Date 2021/7/22 + **/ +@Configuration +public class BeanFactory implements ApplicationContextAware +{ + /** + * Spring应用上下文环境 + */ + private static ApplicationContext context; + + /** + * 实现ApplicationContextAware接口的回调方法,设置上下文环境 + * + * @param applicationContext + */ + @Override + public void setApplicationContext(ApplicationContext applicationContext) + { + context = applicationContext; + } + + /** + * @return ApplicationContext + */ + final public static ApplicationContext getApplicationContext() + { + return context; + } + + public static Object getBean(String name) + { + return context.getBean(name); + } + + public static T getBean(String name, Class requiredType) + { + return context.getBean(name, requiredType); + } + + public static T getBean(Class requiredType) + { + return context.getBean(requiredType); + } + + public static Object getBean(String name, Object... args) + { + return context.getBean(name, args); + } + + public static Map getBeansOfType(Class type) + { + return context.getBeansOfType(type); + } + + public static List getBeans(Class type) + { + Collection beans = context.getBeansOfType(type).values(); + + @SuppressWarnings("unchecked") + List result = (List) Arrays.asList(beans.toArray()); + + return result; + } + + public static boolean containsBean(String name) + { + return context.containsBean(name); + } + + final public static ApplicationContext loadContext() + { + context = new ClassPathXmlApplicationContext("spring_mysql.xml"); + + return context; + } + + public static void main(String[] args) + { +// Map plugins = getBeansOfType(LoginPlugin.class); +// +// for (Map.Entry element: plugins.entrySet()) +// { +// System.out.println(element.getKey() + ": " + element.getValue()); +// } + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/config/CorsInterceptor.java b/wjcy-common/src/main/java/me/zhengjie/config/CorsInterceptor.java new file mode 100644 index 0000000..dd44563 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/CorsInterceptor.java @@ -0,0 +1,36 @@ +package me.zhengjie.config; + +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +/** + *

+ * + *

+ * + * @Author xx + * @Date 2021/7/19 + **/ +@Component +public class CorsInterceptor implements HandlerInterceptor { + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setHeader("Access-Control-Allow-Credentials", "true"); + response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS"); + response.setHeader("Access-Control-Max-Age", "86400"); + response.setHeader("Access-Control-Allow-Headers", "*"); + + // 如果是OPTIONS则结束请求 + if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) { + response.setStatus(HttpStatus.NO_CONTENT.value()); + return false; + } + return true; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/config/CustomIdGenerator.java b/wjcy-common/src/main/java/me/zhengjie/config/CustomIdGenerator.java new file mode 100644 index 0000000..206c77c --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/CustomIdGenerator.java @@ -0,0 +1,39 @@ +package me.zhengjie.config; + + +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.ibatis.reflection.MetaObject; +import org.apache.ibatis.reflection.SystemMetaObject; +import org.springframework.stereotype.Component; + +import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; + +import lombok.extern.slf4j.Slf4j; + +/** + *

+ * 自定义ID生成器 + *

+ * + * @Author xx + * @Date 2021/7/12 + **/ +@Slf4j +@Component +public class CustomIdGenerator implements IdentifierGenerator { + + private final AtomicLong al = new AtomicLong(1); + + @Override + public Long nextId(Object entity) { + //可以将当前传入的class全类名来作为bizKey,或者提取参数来生成bizKey进行分布式Id调用生成. + String bizKey = entity.getClass().getName(); + log.info("bizKey:{}", bizKey); + MetaObject metaObject = SystemMetaObject.forObject(entity); + String name = (String) metaObject.getValue("name"); + final long id = al.getAndAdd(1); + log.info("为{}生成主键值->:{}", name, id); + return id; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/config/DhApiProperties.java b/wjcy-common/src/main/java/me/zhengjie/config/DhApiProperties.java new file mode 100644 index 0000000..0c086a3 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/DhApiProperties.java @@ -0,0 +1,58 @@ +package me.zhengjie.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +/** + * 敦煌Api Properties + * @author rch + * @date 2022-06-27 + */ +@Component +@Configuration +public class DhApiProperties { + + public static String ACCESS_TOKEN; + public static String BUY_ORDER_URL; + public static String BUY_ORDER_METHOD; + public static String BUY_ORDER_V; + public static String PAY_ORDER_URL; + public static String PAY_ORDER_METHOD; + public static String PAY_ORDER_V; + + @Value("${dh.access_token}") + public void setAccessToken(String accessToken) { + DhApiProperties.ACCESS_TOKEN = accessToken; + } + + @Value("${dh.buy_order_url}") + public void setBuyOrderUrl(String buyOrderUrl) { + DhApiProperties.BUY_ORDER_URL = buyOrderUrl; + } + + @Value("${dh.buy_order_method}") + public void setBuyOrderMethod(String buyOrderMethod) { + DhApiProperties.BUY_ORDER_METHOD = buyOrderMethod; + } + + @Value("${dh.buy_order_v}") + public void setBuyOrderV(String buyOrderV) { + DhApiProperties.BUY_ORDER_V = buyOrderV; + } + + @Value("${dh.pay_order_url}") + public void setPayOrderUrl(String payOrderUrl) { + DhApiProperties.PAY_ORDER_URL = payOrderUrl; + } + + @Value("${dh.pay_order_method}") + public void setPayOrderMethod(String payOrderMethod) { + DhApiProperties.PAY_ORDER_METHOD = payOrderMethod; + } + + @Value("${dh.pay_order_v}") + public void setPayOrderV(String payOrderV) { + DhApiProperties.PAY_ORDER_V = payOrderV; + } +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/config/ElPermissionConfig.java b/wjcy-common/src/main/java/me/zhengjie/config/ElPermissionConfig.java new file mode 100644 index 0000000..9ae1fd5 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/ElPermissionConfig.java @@ -0,0 +1,37 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.config; + +import me.zhengjie.utils.SecurityUtils; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.stereotype.Service; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author Zheng Jie + */ +@Service(value = "el") +public class ElPermissionConfig { + + public Boolean check(String ...permissions){ + // 获取当前用户的所有权限 + List elPermissions = SecurityUtils.getCurrentUser().getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()); + // 判断当前用户的所有权限是否包含接口上定义的权限 + return elPermissions.contains("admin") || Arrays.stream(permissions).anyMatch(elPermissions::contains); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/config/FileProperties.java b/wjcy-common/src/main/java/me/zhengjie/config/FileProperties.java new file mode 100644 index 0000000..bf0ebf6 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/FileProperties.java @@ -0,0 +1,60 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.config; + +import lombok.Data; +import me.zhengjie.utils.ElAdminConstant; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * @author Zheng Jie + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "file") +public class FileProperties { + + /** 文件大小限制 */ + private Long maxSize; + + /** 头像大小限制 */ + private Long avatarMaxSize; + + private ElPath mac; + + private ElPath linux; + + private ElPath windows; + + public ElPath getPath(){ + String os = System.getProperty("os.name"); + if(os.toLowerCase().startsWith(ElAdminConstant.WIN)) { + return windows; + } else if(os.toLowerCase().startsWith(ElAdminConstant.MAC)){ + return mac; + } + return linux; + } + + @Data + public static class ElPath{ + + private String path; + + private String avatar; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/config/MvcConfig.java b/wjcy-common/src/main/java/me/zhengjie/config/MvcConfig.java new file mode 100644 index 0000000..8a2da20 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/MvcConfig.java @@ -0,0 +1,31 @@ +package me.zhengjie.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + *

+ * 开放url访问上传到本地的图片 + *

+ * + * @Author xx + * @Date 2021/8/11 + **/ +@Configuration +public class MvcConfig implements WebMvcConfigurer { + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + /* + * 说明:增加虚拟路径(经过本人测试:在此处配置的虚拟路径,用springboot内置的tomcat时有效, + * 用外部的tomcat也有效;所以用到外部的tomcat时不需在tomcat/config下的相应文件配置虚拟路径了,阿里云linux也没问题) + */ + registry.addResourceHandler("/**").addResourceLocations("file:"+SystemConfig.IMG_PATH); + + // 因为doc.html是在jar包里的,需要使用资源处理器注册静态资源。 + registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/"); + registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); + } + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/config/MyMetaObjectHandler.java b/wjcy-common/src/main/java/me/zhengjie/config/MyMetaObjectHandler.java new file mode 100644 index 0000000..1c9a7a6 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/MyMetaObjectHandler.java @@ -0,0 +1,82 @@ +package me.zhengjie.config; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.utils.DateUtil; +import me.zhengjie.utils.SecurityUtils; +import me.zhengjie.utils.StringUtils; +import me.zhengjie.utils.ValidationUtil; +import org.apache.ibatis.reflection.MetaObject; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + *

+ * MyBatis Plus自动填充插入&更新时间 + *

+ * + * @author: zeng + * @since: 2020-07-15 + */ +@Slf4j +@Component +public class MyMetaObjectHandler implements MetaObjectHandler { + + @Override + public void insertFill(MetaObject metaObject) { + log.info("start insert fill ...."); + Object object = metaObject.getOriginalObject(); + String gmName = getGmName(); + if (ObjectUtil.isNotEmpty(gmName)) { + setValue(object,"gmName",gmName); + } + + if (ValidationUtil.isExistFieldName("createdAt", object)) { + setValue(object, "createdAt", DateUtil.getCurrentTime()); + } + + if (ValidationUtil.isExistFieldName("updatedAt", object)) { + setValue(object, "updatedAt", DateUtil.getCurrentTime()); + } + } + + @SneakyThrows + @Override + public void updateFill(MetaObject metaObject) { + Object object = metaObject.getOriginalObject(); + log.info("start update fill ...."); + String gmName = getGmName(); + if (ObjectUtil.isNotNull(gmName)) { + setValue(object,"gmName",gmName); + } + + if (ValidationUtil.isExistFieldName("updatedAt", object)) { + setValue(object, "updatedAt", DateUtil.getCurrentTime()); + } + } + + private void setValue( Object object, String fieldName, Object value) { + try { + if (ObjectUtil.isNotNull(value)) { + String str = "set" + StringUtils.toUpperCase4Index(fieldName); + Method method = object.getClass().getMethod(str, String.class); + method.invoke(object, value); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + + private String getGmName() { + try { + return SecurityUtils.getCurrentUsername(); + } catch (Exception e) { + return null; + } + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/config/MybatisPlusConfig.java b/wjcy-common/src/main/java/me/zhengjie/config/MybatisPlusConfig.java new file mode 100644 index 0000000..56e1883 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/MybatisPlusConfig.java @@ -0,0 +1,32 @@ +package me.zhengjie.config; + +import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * @author + * @date + */ +@Configuration +@ConditionalOnClass(value = {PaginationInterceptor.class}) +@EnableTransactionManagement +public class MybatisPlusConfig { + @Bean + public PaginationInterceptor paginationInterceptor() { + PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); + return paginationInterceptor; + } + + /** + * 乐观锁 :CAS方案解决 当要更新一条记录的时候,希望这条记录没有被别人更新 + * @return + */ + @Bean + public OptimisticLockerInterceptor optimisticLockerInterceptor() { + return new OptimisticLockerInterceptor(); + } +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/config/PlatsProperties.java b/wjcy-common/src/main/java/me/zhengjie/config/PlatsProperties.java new file mode 100644 index 0000000..64e5da2 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/PlatsProperties.java @@ -0,0 +1,44 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.config; + +import lombok.Data; +import me.zhengjie.utils.ElAdminConstant; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * @author rch + * @date 2022-07-06 + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "plats") +public class PlatsProperties { + + private DhProperties dh; + + + @Data + public static class DhProperties{ + private String buyOrderUrl; + private String buyOrderMethod; + private String buyOrderv; + private String payOrder_url; + private String payOrderMethod; + private String payOrderv; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/config/PropertiesConfig.java b/wjcy-common/src/main/java/me/zhengjie/config/PropertiesConfig.java new file mode 100644 index 0000000..c0f9b9f --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/PropertiesConfig.java @@ -0,0 +1,30 @@ +package me.zhengjie.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +/** + *

+ * + *

+ * + * @Author xx + * @Date 2021/7/26 + **/ +@Data +@Component +@Configuration +@ConfigurationProperties(prefix = "config") +public class PropertiesConfig { + + private String uploadPrefix; + private Map uploadImgPath; + private List excludeUrlList; + private List sustainImgFormat; + /** 放掉的api 校验token */ + private String apiToken; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/config/RedisConfig.java b/wjcy-common/src/main/java/me/zhengjie/config/RedisConfig.java new file mode 100644 index 0000000..5366b99 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/RedisConfig.java @@ -0,0 +1,223 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.config; + +import cn.hutool.core.lang.Assert; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.parser.ParserConfig; +import com.alibaba.fastjson.serializer.SerializerFeature; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.utils.StringUtils; +import org.apache.commons.codec.digest.DigestUtils; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cache.Cache; +import org.springframework.cache.annotation.CachingConfigurerSupport; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.interceptor.CacheErrorHandler; +import org.springframework.cache.interceptor.KeyGenerator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.serializer.RedisSerializationContext; +import org.springframework.data.redis.serializer.RedisSerializer; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Zheng Jie + * @date 2018-11-24 + */ +@Slf4j +@Configuration +@EnableCaching +@ConditionalOnClass(RedisOperations.class) +@EnableConfigurationProperties(RedisProperties.class) +public class RedisConfig extends CachingConfigurerSupport { + + /** + * 设置 redis 数据默认过期时间,默认2小时 + * 设置@cacheable 序列化方式 + */ + @Bean + public RedisCacheConfiguration redisCacheConfiguration(){ + FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); + RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig(); + configuration = configuration.serializeValuesWith(RedisSerializationContext. + SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofHours(6)); + return configuration; + } + + @SuppressWarnings("all") + @Bean(name = "redisTemplate") + @ConditionalOnMissingBean(name = "redisTemplate") + public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { + RedisTemplate template = new RedisTemplate<>(); + //序列化 + FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); + // value值的序列化采用fastJsonRedisSerializer + template.setValueSerializer(fastJsonRedisSerializer); + template.setHashValueSerializer(fastJsonRedisSerializer); + // 全局开启AutoType,这里方便开发,使用全局的方式 + ParserConfig.getGlobalInstance().setAutoTypeSupport(true); + // 建议使用这种方式,小范围指定白名单 + // ParserConfig.getGlobalInstance().addAccept("me.zhengjie.domain"); + // key的序列化采用StringRedisSerializer + template.setKeySerializer(new StringRedisSerializer()); + template.setHashKeySerializer(new StringRedisSerializer()); + template.setConnectionFactory(redisConnectionFactory); + return template; + } + + @Bean + public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { + StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(); + stringRedisTemplate.setConnectionFactory(redisConnectionFactory); + return stringRedisTemplate; + } + + /** + * 自定义缓存key生成策略,默认将使用该策略 + */ + @Bean + @Override + public KeyGenerator keyGenerator() { + return (target, method, params) -> { + Map container = new HashMap<>(3); + Class targetClassClass = target.getClass(); + // 类地址 + container.put("class",targetClassClass.toGenericString()); + // 方法名称 + container.put("methodName",method.getName()); + // 包名称 + container.put("package",targetClassClass.getPackage()); + // 参数列表 + for (int i = 0; i < params.length; i++) { + container.put(String.valueOf(i),params[i]); + } + // 转为JSON字符串 + String jsonString = JSON.toJSONString(container); + // 做SHA256 Hash计算,得到一个SHA256摘要作为Key + return DigestUtils.sha256Hex(jsonString); + }; + } + + @Bean + @Override + public CacheErrorHandler errorHandler() { + // 异常处理,当Redis发生异常时,打印日志,但是程序正常走 + log.info("初始化 -> [{}]", "Redis CacheErrorHandler"); + return new CacheErrorHandler() { + @Override + public void handleCacheGetError(RuntimeException e, Cache cache, Object key) { + log.error("Redis occur handleCacheGetError:key -> [{}]", key, e); + } + + @Override + public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) { + log.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e); + } + + @Override + public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) { + log.error("Redis occur handleCacheEvictError:key -> [{}]", key, e); + } + + @Override + public void handleCacheClearError(RuntimeException e, Cache cache) { + log.error("Redis occur handleCacheClearError:", e); + } + }; + } + +} + +/** + * Value 序列化 + * + * @author / + * @param + */ + class FastJsonRedisSerializer implements RedisSerializer { + + private final Class clazz; + + FastJsonRedisSerializer(Class clazz) { + super(); + this.clazz = clazz; + } + + @Override + public byte[] serialize(T t) { + if (t == null) { + return new byte[0]; + } + return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(StandardCharsets.UTF_8); + } + + @Override + public T deserialize(byte[] bytes) { + if (bytes == null || bytes.length <= 0) { + return null; + } + String str = new String(bytes, StandardCharsets.UTF_8); + return JSON.parseObject(str, clazz); + } + +} + +/** + * 重写序列化器 + * + * @author / + */ +class StringRedisSerializer implements RedisSerializer { + + private final Charset charset; + + StringRedisSerializer() { + this(StandardCharsets.UTF_8); + } + + private StringRedisSerializer(Charset charset) { + Assert.notNull(charset, "Charset must not be null!"); + this.charset = charset; + } + + @Override + public String deserialize(byte[] bytes) { + return (bytes == null ? null : new String(bytes, charset)); + } + + @Override + public byte[] serialize(Object object) { + String string = JSON.toJSONString(object); + if (StringUtils.isBlank(string)) { + return null; + } + string = string.replace("\"", ""); + return string.getBytes(charset); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/config/RedissonConfig.java b/wjcy-common/src/main/java/me/zhengjie/config/RedissonConfig.java new file mode 100644 index 0000000..192fc03 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/RedissonConfig.java @@ -0,0 +1,48 @@ +package me.zhengjie.config; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.config.Config; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +/** + *

+ *redisson 配置类 + *

+ * + * @Author xx + * @Date 2021/8/11 + **/ +@Configuration +@Data +public class RedissonConfig { + @Value("${spring.redis.host}") + private String host; + + @Value("${spring.redis.port}") + private String port; + + @Value("${spring.redis.password}") + private String password; + + @Value("${spring.redis.database}") + private Integer database; + + @Bean + public RedissonClient getRedisson(){ + + Config config = new Config(); + // 若redis为设置密码,将密码设置为null (防止password='' 运行报错) + if (ObjectUtil.isEmpty(password)) { + password = null; + } + config.useSingleServer().setAddress("redis://" + host + ":" + port).setDatabase(database).setPassword(password); + //添加主从配置 +// config.useMasterSlaveServers().setMasterAddress("").setPassword("").addSlaveAddress(new String[]{"",""}); + + return Redisson.create(config); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/config/RsaProperties.java b/wjcy-common/src/main/java/me/zhengjie/config/RsaProperties.java new file mode 100644 index 0000000..a3594cd --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/RsaProperties.java @@ -0,0 +1,38 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * @author Zheng Jie + * @website https://el-admin.vip + * @description + * @date 2020-05-18 + **/ +@Data +@Component +public class RsaProperties { + + public static String privateKey; + + @Value("${rsa.private_key}") + public void setPrivateKey(String privateKey) { + RsaProperties.privateKey = privateKey; + } +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/config/SwaggerConfig.java b/wjcy-common/src/main/java/me/zhengjie/config/SwaggerConfig.java new file mode 100644 index 0000000..1c354b3 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/SwaggerConfig.java @@ -0,0 +1,217 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.ParameterBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.schema.ModelRef; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.Contact; +import springfox.documentation.service.Parameter; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc; + +import java.util.ArrayList; +import java.util.List; + +/** + * api页面 /doc.html + * @author Zheng Jie + * @date 2018-11-23 + */ +@Configuration +@EnableSwagger2WebMvc//新版本 +public class SwaggerConfig { + + @Bean(value = "buildBaseDocket") + public Docket buildBaseDocket() { + return new Docket(DocumentationType.SWAGGER_2) + .groupName("基础业务接口") + .apiInfo(buildApiInf()) + .select() + //controller包路径 + .apis(RequestHandlerSelectors.basePackage("me.zhengjie.modules.group.controller.base")) + .paths(PathSelectors.any()) + .build() + .globalOperationParameters(getParmeter()); + } + + @Bean(value = "buildOtherDocket") + public Docket buildOtherDocket() { + return new Docket(DocumentationType.SWAGGER_2) + .groupName("其他业务接口") + .apiInfo(buildApiInf()) + .select() + //controller包路径 + .apis(RequestHandlerSelectors.basePackage("me.zhengjie.modules.capital.controller.base")) + .paths(PathSelectors.any()) + .build() + .globalOperationParameters(getParmeter()); + } + + @Bean(value = "buildCallBackDocket") + public Docket buildCallBackDocket() { + return new Docket(DocumentationType.SWAGGER_2) + .groupName("回调业务接口") + .apiInfo(buildApiInf()) + .select() + //controller包路径 + .apis(RequestHandlerSelectors.basePackage("me.zhengjie.modules.group.controller.callbcak")) + .paths(PathSelectors.any()) + .build() + .globalOperationParameters(getParmeter()); + } + + @Bean(value = "buildSystemDocket") + public Docket buildSystemDocket() { + return new Docket(DocumentationType.SWAGGER_2) + .groupName("系统业务接口") + .apiInfo(buildApiInf()) + .select() + //controller包路径 + .apis(RequestHandlerSelectors.basePackage("me.zhengjie.modules.system.rest")) + .paths(PathSelectors.any()) + .build() + .globalOperationParameters(getParmeter()); + } + + /** + * 描述信息 + */ + private ApiInfo buildApiInf() { + return new ApiInfoBuilder() + // 文档标题 + .title("旺嘉分销管理系统-接口文档") + // 版本信息 + .version("1.0") + // 文档描述 + .description("旺嘉分销管理系统管理文档") + // 版权地址 + .termsOfServiceUrl("http://www.wjcy.com") + // 版权 + .license("旺嘉创亿") + // 联系人信息 + .contact(new Contact("rch", "http://www.baidu.com", "baidu@qq.com")) + .build(); + } + + + public List getParmeter() { + ParameterBuilder tokenPar = new ParameterBuilder(); + List pars = new ArrayList<>(); + tokenPar.name("Authorization").description("令牌").defaultValue("设置token默认值").modelRef(new ModelRef("string")).parameterType("header").required(false).build(); + pars.add(tokenPar.build()); + return pars; + } + + +// @Bean +// @SuppressWarnings("all") +// public Docket createRestApi() { +// return new Docket(DocumentationType.SWAGGER_2) +// .enable(enabled) +// .pathMapping("/") +// .apiInfo(apiInfo()) +// .select() +// .paths(Predicates.not(PathSelectors.regex("/error.*"))) +// .paths(PathSelectors.any()) +// .build() +// //添加登陆认证 +// .securitySchemes(securitySchemes()) +// .securityContexts(securityContexts()); +// } +// +// private ApiInfo apiInfo() { +// return new ApiInfoBuilder() +// .description("一个简单且易上手的 Spring boot 后台管理框架") +// .title("EL-ADMIN 接口文档") +// .version("2.6") +// .build(); +// } +// +// private List securitySchemes() { +// //设置请求头信息 +// List securitySchemes = new ArrayList<>(); +// ApiKey apiKey = new ApiKey(tokenHeader, tokenHeader, "header"); +// securitySchemes.add(apiKey); +// return securitySchemes; +// } +// +// private List securityContexts() { +// //设置需要登录认证的路径 +// List securityContexts = new ArrayList<>(); +// // ^(?!auth).*$ 表示所有包含auth的接口不需要使用securitySchemes即不需要带token +// // ^标识开始 ()里是一子表达式 ?!/auth表示匹配不是/auth的位置,匹配上则添加请求头,注意路径已/开头 .表示任意字符 *表示前面的字符匹配多次 $标识结束 +// securityContexts.add(getContextByPath()); +// return securityContexts; +// } +// +// private SecurityContext getContextByPath() { +// return SecurityContext.builder() +// .securityReferences(defaultAuth()) +// .forPaths(PathSelectors.regex("^(?!/auth).*$")) +// .build(); +// } +// +// private List defaultAuth() { +// List securityReferences = new ArrayList<>(); +// AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); +// AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; +// authorizationScopes[0] = authorizationScope; +// securityReferences.add(new SecurityReference(tokenHeader, authorizationScopes)); +// return securityReferences; +// } +//} +// +///** +// * 将Pageable转换展示在swagger中 +// */ +//@Configuration +//class SwaggerDataConfig { +// +// @Bean +// public AlternateTypeRuleConvention pageableConvention(final TypeResolver resolver) { +// return new AlternateTypeRuleConvention() { +// @Override +// public int getOrder() { +// return Ordered.HIGHEST_PRECEDENCE; +// } +// +// @Override +// public List rules() { +// return newArrayList(newRule(resolver.resolve(Pageable.class), resolver.resolve(Page.class))); +// } +// }; +// } +// +// @ApiModel +// @Data +// private static class Page { +// @ApiModelProperty("页码 (0..N)") +// private Integer page; +// +// @ApiModelProperty("每页显示的数目") +// private Integer size; +// +// @ApiModelProperty("以下列格式排序标准:property[,asc | desc]。 默认排序顺序为升序。 支持多种排序条件:如:id,asc") +// private List sort; +// } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/config/SystemConfig.java b/wjcy-common/src/main/java/me/zhengjie/config/SystemConfig.java new file mode 100644 index 0000000..264554a --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/SystemConfig.java @@ -0,0 +1,97 @@ +package me.zhengjie.config; + + +import cn.hutool.core.lang.Snowflake; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; +/** + *

+ * 系统配置类,从配置文件中注入配置信息 + *

+ * + * @Author xx + * @Date 2021/7/21 + **/ +@Component +@Configuration +public class SystemConfig { + + /** 聊天室默认头像 */ + public static String DEFAULT_MEMBER_HEAD = "/capital/chat/head/default.jpg"; + /** + * 图片存放的绝对路径 + */ + public static String IMG_PATH; + /** + * 静态资源访问路径(返回前端时添加) + */ + public static String FILE_VISIT_ADDR; + /** + * 文件上传接口后缀,用来放行xss过滤 + */ + public static String UPLOAD_SUFFIX; + /** + * 单文件上传大小限制,单位 :MB + */ + public static Integer MAX_FILE_SIZE; + /** + * 视频单文件上传大小限制,单位 :MB + */ + public static Integer VIDEO_MAX_FILE_SIZE; + + /** 多语言文件路径 */ + public static String LANGUAGE_PATH; + + public static final String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn4jGDcYFGhxNaIKO+oK6ALzHzXupk7+aYa7FYlnS6A/AM9cwgzdksGqfKi7//XDlrqp5jyfecciU7KW7xzs9g+8ZHGy8IEVBqhsOBOjPvi3twc9kdWPhtsRY5X1J2PfRilT/jIMDpBflLf0CrrrPXezKENwRMxlkmSOZqvg0sOwIDAQAB"; + public static final String privateKey = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKfiMYNxgUaHE1ogo76groAvMfNe6mTv5phrsViWdLoD8Az1zCDN2Swap8qLv/9cOWuqnmPJ95xyJTspbvHOz2D7xkcbLwgRUGqGw4E6M++Le3Bz2R1Y+G2xFjlfUnY99GKVP+MgwOkF+Ut/QKuus9d7MoQ3BEzGWSZI5mq+DSw7AgMBAAECgYEAlnQ7JW5aicdSC4qG1LcRy+T/4filHXJ1+RFCbX7g+ze+MQ8zMg7o2wLEbtvRZFvVRe0xZ4K/+p+9SAj42ZIa/H7ktxhkaxNHVYHVafAuLu2/VFCc7vNPUVu5Fx1xLEg0q2q5TJ2OPlzh9aARh4PW1IetLPBeQSi1qUHVrhPQvskCQQDSxIYv3dpFw9ljqtSriNtIfHSqYAATGtp5SvFfw63fRtvxK6X5Zkdy9ExYe9SOm9u3Q7P4QEKbd4Rbf22Zp2O3AkEAy+mjDGtUP7unrfpuEpe/b+uMPB5+jcmTDDsu3ReZcTzH6BFCqeyR3FBsApLSVWLXuJNKfdKGmH/SwXv2nFUjnQJBAMUE7CKmkbkRYI7oS7ClV8YkgLIa1zcErSEgyw0nz8qdZE/G63l9AGEWuJ8l8gX076gaY4s2Fo1ZZaJaNcuiS3UCQCXFxbpLN3QG4uzLcxBmo8OrsnKAg5joOiEN5YR3FqlvROisKdkoRWy2SQvA/s1qXeOHBUmBcgVVyEinGeujqdECQAeBvDraddWeGuqTEtOXJhQiPxmahUWE2h5htpFdK3+cVt5HiRM89SLM64kHAx7m/RxiGscnhbbXUvSx0H/36R0="; + + /** websocket服务器连接地址 */ + public static String WS_URL; + /** 百度翻译 APPID */ + public static String BAIDU_APPID; + /** 百度翻译privateKey */ + public static String BAIDU_PRIVATEKEY; + /** 百度翻译URL */ + public static final String BAIDU_URL = "https://fanyi-api.baidu.com/api/trans/vip/translate"; + + public static String IP2REGION_DB_PATH; + @Value("${system.imgPath}") + public void setImgPath(String imgPath) { + IMG_PATH = imgPath; + } + + @Value("${system.fileVisitAddr}") + public void setFileVisitAddr(String fileVisitAddr) { + FILE_VISIT_ADDR = fileVisitAddr; + } + @Value("${system.uploadSuffix}") + public void setUploadSuffix(String uploadSuffix) { + UPLOAD_SUFFIX = uploadSuffix; + } + @Value("${system.maxFileSize}") + public void setMaxFileSize(Integer maxFileSize) { + MAX_FILE_SIZE = maxFileSize; + } + + @Value("${system.maxVideoFileSize}") + public void setVideoMaxFileSize(Integer maxVideoFileSize) { + VIDEO_MAX_FILE_SIZE = maxVideoFileSize; + } + + @Value("${system.ip2regionDbPath}") + public void setIp2regionDbPath(String ip2regionDbPath) { + IP2REGION_DB_PATH = ip2regionDbPath; + } + + @Value("${system.languagePath}") + public void setLanguagePath(String languagePath) { + LANGUAGE_PATH = languagePath; + } + + @Bean + public Snowflake snowFlakeInit() { + return new Snowflake(2, 3); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/config/YdApiProperties.java b/wjcy-common/src/main/java/me/zhengjie/config/YdApiProperties.java new file mode 100644 index 0000000..d0eb788 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/YdApiProperties.java @@ -0,0 +1,34 @@ +package me.zhengjie.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +/** + * 影刀Api Properties + * @author rch + * @date 2022-07-27 + */ +@Component +@Configuration +public class YdApiProperties { + + public static String ACCESS_KEY_ID; + public static String ACCESS_KEY_SECRET; + public static String CALLBACK; + + @Value("${yd.accessKeyId}") + public void setAccessKeyId(String accessKeyId) { + ACCESS_KEY_ID = accessKeyId; + } + + @Value("${yd.accessKeySecret}") + public void setAccessKeySecret(String accessKeySecret) { + ACCESS_KEY_SECRET = accessKeySecret; + } + + @Value("${yd.callback}") + public void setCALLBACK(String CALLBACK) { + YdApiProperties.CALLBACK = CALLBACK; + } +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/config/constant/Constants.java b/wjcy-common/src/main/java/me/zhengjie/config/constant/Constants.java new file mode 100644 index 0000000..df0364a --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/config/constant/Constants.java @@ -0,0 +1,30 @@ +package me.zhengjie.config.constant; + +/** + *

+ * 常量实体类 + *

+ * + * @author: rch + * @date: 2021-11-23 + */ +public class Constants { + /** redis token前缀*/ + public static final String TOKEN_PREFIX = "sessions:"; + /** 前端token请求头名称*/ + public static final String TOKEN_HEAD_NAME = "token"; + /** redis 手机验证码前缀*/ + public static final String PHONE_VERIFY_CODE = "phone:"; + /** 表单重复提交时间间隔,单位;秒 */ + public static final long FORM_SUB_SECOND = 1L; + /** 表单重复提交验证的token前缀*/ + public static final String FORM_SUB_TOKEN = "formSubToken:"; + /** 用户默认头像地址 */ + public static final String USER_DEFAULT_HEAD = "/sports/file/userHead/default.jpg"; + + /** 代理后台用户token redis key前缀 */ + public static final String PROXY_ADMIN_TOKEN_PREFIX = "proxy:sessions:"; + + /** 代理后台 访问量统计 "pageviews:"+invite_code*/ + public final static String PAGE_VIEWS_REDIS_PREFIX = "pageviews:"; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/constant/Constants.java b/wjcy-common/src/main/java/me/zhengjie/constant/Constants.java new file mode 100644 index 0000000..7a05f0c --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/constant/Constants.java @@ -0,0 +1,16 @@ +package me.zhengjie.constant; + +/** + * 通用常量信息 + * + * @author rch + * @create 2022-08-01 + */ +public class Constants { + public final static String REBOT_STATU = "https://api.winrobot360.com/oapi/dispatch/v2/client/query"; + public final static String GET_SECRET = "https://api.winrobot360.com/oapi/token/v2/token/create"; + public final static String STAT_JOB_URL = "https://api.winrobot360.com/oapi/dispatch/v2/job/start"; + public final static String QUERY_JOB_URL = "https://api.winrobot360.com/oapi/dispatch/v2/job/query"; + + public final static String ERP_AUTH_TOKEN = "ErpAuthToken ddabd37130f86a8ee5f03887552c0b69"; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/constant/PublicConstant.java b/wjcy-common/src/main/java/me/zhengjie/constant/PublicConstant.java new file mode 100644 index 0000000..985b053 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/constant/PublicConstant.java @@ -0,0 +1,56 @@ +package me.zhengjie.constant; + +/** + * + * @Description 通用常量 + * @Date 2022/1/20 + * @Author zeng + */ +public interface PublicConstant { + + /** 缓存失效时间 */ + Integer CACHE_OVER_TIME = 1800; + + /** 设备使用缓存前缀 */ + String REBOT_PREFIX = "rebot:%s"; + + /** 全局系统设置 */ + String SETTING_SITE_PREFIX = "setting_site:%s"; + + /** 更新会员信息 */ + String MEMBER_PROFIT_LOCK_KEY = "member_update_key:%s"; + + String DH_REQUEST_SUCCESS_STATUS_CODE = "00000000"; + + String RESPONSE_SUCCESS = "SUCCESS"; + + Integer EXPORT_EXCEL_FILE_TYPE = 11; + + /** 刷单信息对应执行过的买家信息 */ + String CLICK_FARMING_EXEC_ID_SET = "click_farming_exec:id:%s"; + + /** 执行任务前缀 */ + String JOB_UUID_KEY_PREFIX = "JOB_UUID_KEY:%s"; + + static String getMemberUpdateKeyPrefix(Long memberId) { + return String.format(MEMBER_PROFIT_LOCK_KEY, memberId); + } + + static String getJobUuidKeyPrefix(String jobUuid) { + return String.format(JOB_UUID_KEY_PREFIX, jobUuid); + } + + /** + * 刷单信息对应执行过的买家Id集合拼接 + * @param clickFarmingId + * @return + */ + static String getClickFarmingExecBuyerIdPrefix(Long clickFarmingId) { + return String.format(CLICK_FARMING_EXEC_ID_SET, clickFarmingId); + } + + + static String getRebotKeyPrefix(String accountName) { + return String.format(REBOT_PREFIX, accountName); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/CtApplyDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/CtApplyDao.java new file mode 100644 index 0000000..a4abe36 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/CtApplyDao.java @@ -0,0 +1,39 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import me.zhengjie.entity.CtApply; +import me.zhengjie.service.vo.CtApplyListVO; +import me.zhengjie.service.vo.CtBuyerListVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * 影刀应用信息(CtApply)表数据库访问层 + * + * @author rch + * @since 2022-07-23 + */ +@Mapper +public interface CtApplyDao extends BaseMapper { + + + @Select("select * from ct_apply ${ew.customSqlSegment}") + IPage searchPageList(IPage page, Wrapper ew); + + /** + * 获取所有应用名称 + * @return List + */ + @Select("select id,name, platform_id from ct_apply") + List getAllApplyName(); + + @Select("select * from ct_apply where task_name = #{taskName} and method_name = #{method}") + CtApply getApplyByTaskAndMethod(String taskName, String method); +} + + + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/CtBrowseDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/CtBrowseDao.java new file mode 100644 index 0000000..4054b15 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/CtBrowseDao.java @@ -0,0 +1,61 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import me.zhengjie.entity.CtBrowse; +import me.zhengjie.service.vo.CtBrowseDetailVO; +import me.zhengjie.service.vo.CtBrowseListVO; +import me.zhengjie.service.vo.CtBuyerListVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +/** + * 刷单-订单信息(CtBrowse)表数据库访问层 + * + * @author rch + * @since 2022-11-04 + */ +@Mapper +public interface CtBrowseDao extends BaseMapper { + + /** + * 分页查询 + * @param page + * @param ew + */ +// @Select("select * from ct_browse ${ew.customSqlSegment} ") + @Select("SELECT\n" + + "\tctBrowse.id,\n" + + "\tctBrowse.buyer_id,\n" + + "\tctBrowse.link_url,\n" + + "\tctBrowse.created_at,\n" + + "\tctBrowse.updated_at,\n" + + "\tctBrowse.payment_results,\n" + + "\tctBrowse.status,\n" + + "\tctBrowse.gm_name,\n" + + "\tctBuyer.contntry_short as country,\n" + + "\tctBuyer.account\n" + + "FROM\n" + + "\tct_browse ctBrowse\n" + + "LEFT JOIN \n" + + "\tct_buyer ctBuyer \n" + + "ON \n" + + "\tctBrowse.buyer_id = ctBuyer.id ${ ew.customSqlSegment}") + IPage searchPageList(IPage page, Wrapper ew); + + @Select("select * from ct_browse where id = #{id} for update") + CtBrowse getByIdLock(Long id); + + @Select("SELECT\n" + + "\tctBrowse.*,\n" + + "\tctBuyer.account,\n" + + "\tctBuyer.contntry_short as country\n" + + "FROM\n" + + "\tct_browse ctBrowse\n" + + "\tLEFT JOIN ct_buyer ctBuyer ON ctBrowse.buyer_id = ctBuyer.id \n" + + "WHERE\n" + + "\tctBrowse.id = #{id}") + CtBrowseDetailVO getBrowseDetailById(Long id); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/CtBuyerDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/CtBuyerDao.java new file mode 100644 index 0000000..358dcb1 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/CtBuyerDao.java @@ -0,0 +1,56 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import me.zhengjie.entity.CtBuyer; +import me.zhengjie.service.vo.CtBuyerDetailVO; +import me.zhengjie.service.vo.CtBuyerListVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * 买家信息表(CtBuyer)表数据库访问层 + * + * @author rch + * @since 2022-06-22 + */ +@Mapper +public interface CtBuyerDao extends BaseMapper { + + // @Select("select t1.*, t2.name as companyName, t3.id as cardId, t3.number as number, t3.pwd as cardPwd, t3.holder_surname as holderSurname, t3.holder_name as holderName, t4.id as vpnId, t4.ip_address as ipAddress, t4.link as vpn from ct_buyer t1 left join ct_company t2 on t1.company_id = t2.id left join ct_card t3 on t1.card_id = t3.id left join ct_vpn t4 on t1.vpn_id = t4.id ${ew.customSqlSegment} ") + @Select("SELECT\n" + + "\tt1.*,\n" + + "\tt2.NAME AS companyName,\n" + + "\tt5.NAME AS platformName,\n" + + "\tt3.id AS cardId,\n" + + "\tt3.number AS number,\n" + + "\tt3.pwd AS cardPwd,\n" + + "\tt3.holder_surname AS holderSurname,\n" + + "\tt3.holder_name AS holderName,\n" + + "\tt4.id AS vpnId,\n" + + "\tt4.ip_address AS ipAddress,\n" + + "\tt4.link AS vpn \n" + + "FROM\n" + + "\tct_buyer t1\n" + + "\tLEFT JOIN ct_company t2 ON t1.company_id = t2.id\n" + + "\tLEFT JOIN ct_platform t5 ON t1.platform_id = t5.id\n" + + "\tLEFT JOIN ct_card t3 ON t1.card_id = t3.id\n" + + "\tLEFT JOIN ct_vpn t4 ON t1.vpn_id = t4.id ${ ew.customSqlSegment }") + IPage searchPageList(IPage page, Wrapper ew); + + @Select("select t1.*, t2.name as companyName, t3.ip_address as ipAddress, t3.link as vpn, t4.number, t4.pwd as cardPwd, t4.holder_surname as holderSurname, t4.holder_name as holderName from ct_buyer t1 left join ct_company t2 on t1.company_id = t2.id left join ct_vpn t3 on t1.vpn_id = t3.id left join ct_card t4 on t1.card_id = t4.id where t1.id = ${id}") + CtBuyerDetailVO getDetailById(Long id); + + @Select("select account from ct_buyer") + List getAllAccount(); + + @Select("select pwd from ct_buyer where account = #{name}") + String getPwdByName(String name); + + @Select("select id, occupy_status, company_id, platform_id from ct_buyer where account = #{buyerName} for update") + CtBuyer getBuyerOccupyStatusLock(String buyerName); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/CtCardDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/CtCardDao.java new file mode 100644 index 0000000..c43dc2d --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/CtCardDao.java @@ -0,0 +1,34 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import me.zhengjie.entity.CtCard; +import me.zhengjie.entity.CtCardInfo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * 信用卡信息(CtCard)表数据库访问层 + * + * @author rch + * @since 2022-07-07 + */ +@Mapper +public interface CtCardDao extends BaseMapper { + + @Select("select number from ct_card") + List getNumberList(); + + //@Select("select id,number from ct_card where number in ${number}") + @Select({ + "" + }) + List getCardInfoByNumber(List number); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/CtClickFarmingDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/CtClickFarmingDao.java new file mode 100644 index 0000000..1669d9e --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/CtClickFarmingDao.java @@ -0,0 +1,90 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import me.zhengjie.entity.CtBuyerClickSuccess; +import me.zhengjie.entity.CtClickFarmYdParams; +import me.zhengjie.entity.CtClickFarming; +import me.zhengjie.service.vo.CtClickFarmEditDetailVO; +import me.zhengjie.service.vo.CtClickFarmingDetailVO; +import me.zhengjie.service.vo.CtClickFarmingVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * 刷单Excel信息(CtClickFarming)表数据库访问层 + * + * @author rch + * @since 2022-08-16 + */ +@Mapper +public interface CtClickFarmingDao extends BaseMapper { + + // @Select("select farming.* from ct_click_farming farming left join ct_click_order clickOrder on farming.ct_click_order_id = clickOrder.id ${ew.customSqlSegment} ") + @Select("SELECT\n" + + "\tfarming.*,\n" + + "\tbuyer.contntry_short as country,\n" + + "\tbuyer.account\n" + + "FROM\n" + + "\tct_click_farming farming\n" + + "\tLEFT JOIN ct_click_order clickOrder ON farming.ct_click_order_id = clickOrder.id\n" + + "\tLEFT JOIN ct_buyer buyer ON buyer.id = farming.buyer_id\n" + + "${ew.customSqlSegment}") + IPage searchPageList(IPage page, Wrapper ew); + + @Select("select * from ct_click_farming where id = #{id} for update") + CtClickFarming getByIdLock(Long id); + + @Select("SELECT t1.*, t2.account AS buyer_name FROM ct_click_farming t1 LEFT JOIN ct_buyer t2 ON t1.buyer_id = t2.id where t1.id = #{id}") + CtClickFarmEditDetailVO getEditDetailById(Long id); + + @Select("SELECT t1.*, t2.account AS buyer_name FROM ct_click_farming t1 LEFT JOIN ct_buyer t2 ON t1.buyer_id = t2.id where t1.id = #{id}") + CtClickFarmingDetailVO getDetailById(Long id); + +// @Select("select buyer_id, count(1) as successCount from ct_click_farming where account != #{buyerAccount} and `status` = 3 GROUP BY buyer_id;") +// @Select("SELECT\n" + +// "\tclick.buyer_id,\n" + +// "\tcount( 1 ) AS successCount \n" + +// "FROM\n" + +// "\tct_click_farming AS click \t\n" + +// "\tLEFT JOIN ct_buyer AS buyer ON buyer.id = click.buyer_id and click.account != #{buyerAccount} AND click.status = 3\n" + +// "\tAND buyer.occupy_status = 2 AND buyer.country = #{country} and click.shopName != #{shopName} And ct\n" + +// "GROUP BY\n" + +// "\tbuyer_id;") +// @Select("SELECT click.buyer_id, count( 1 ) AS successCount, click.created_at FROM ct_click_farming AS click LEFT JOIN ct_buyer AS buyer ON buyer.id = click.buyer_id AND click.account != #{buyerAccount} AND click.STATUS = 3 AND buyer.occupy_status = 2 AND buyer.country = #{country} AND click.shop_name != #{shopName} GROUP BY buyer_id HAVING created_at < DATE_SUB(CURDATE(), INTERVAL 1 MONTH)") + @Select("SELECT click.buyer_id, count(1) AS successCount, click.status, click.created_at FROM ct_click_farming AS click LEFT JOIN ct_buyer AS buyer ON buyer.id = click.buyer_id AND click.account != #{buyerAccount} AND buyer.occupy_status = 2 AND buyer.country = #{country} AND click.shop_name != #{shopName} GROUP BY buyer_id HAVING created_at < DATE_SUB(CURDATE(), INTERVAL 1 MONTH) AND STATUS = 3") + List ruleGetCtBuyer(String buyerAccount, String country, String shopName); + + @Select("SELECT\n" + + "\tfarming.id,\n" + + "\tfarming.key_word as keyWord,\n" + + "\tfarming.number,\n" + + "\tfarming.params_type,\n" + + "\tfarming.specification,\n" + + "\tfarming.color,\n" + + "\tfarming.item,\n" + + "\tfarming.exchange,\n" + + "\tfarming.link,\n" + + "\tfarming.section_min as sectionMin,\n" + + "\tfarming.section_max as sectionMax,\n" + + "\tfarming.amessage,\n" + + "\tbuyer.contntry_short as country,\n" + + "\tbuyer.account,\n" + + "\tbuyer.pwd,\n" + + "\tctVpn.link as vpnShare,\n" + + "\tctCard.term_of_validity as termOfValidity,\n" + + "\tCONCAT(ctCard.holder_surname, \" \",ctCard.holder_name) AS cardName,\n" + + "\tctCard.number as cardNumber,\n" + + "\tctCard.pwd as cardPwd\n" + + "FROM\n" + + "\tct_click_farming farming\n" + + "\tLEFT JOIN ct_click_order clickOrder ON farming.ct_click_order_id = clickOrder.id\n" + + "\tLEFT JOIN ct_buyer buyer ON buyer.id = farming.buyer_id\n" + + "\tLEFT JOIN ct_vpn ctVpn ON buyer.vpn_id = ctVpn.id\n" + + "\tLEFT JOIN ct_card ctCard ON buyer.card_id = ctCard.id where farming.id = #{id}") + CtClickFarmYdParams getCtClickFarmYdParams(Long id); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/CtClickOrderDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/CtClickOrderDao.java new file mode 100644 index 0000000..b90cfa3 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/CtClickOrderDao.java @@ -0,0 +1,100 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import me.zhengjie.entity.CtClickFarmingOrderInfo; +import me.zhengjie.entity.CtClickOrder; +import me.zhengjie.service.vo.CtClickOrderDetailVO; +import me.zhengjie.service.vo.CtClickOrderListVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +/** + * 刷单-订单信息(CtClickOrder)表数据库访问层 + * + * @author rch + * @since 2022-09-14 + */ +@Mapper +public interface CtClickOrderDao extends BaseMapper { + + /** + * 分页查询 + * @param page + * @param ew + */ + //TODO sql 修改 +// @Select("SELECT\n" + +// "\t`order`.platform_id, \n" + +// "\t`order`.company_id, \n" + +// "\t`order`.id, \n" + +// "\t`order`.created_at, \n" + +// "\t`order`.updated_at, \n" + +// "\t`order`.amount, \n" + +// "\t`order`.shop, \n" + +// "\t`order`.order_id, \n" + +// "\t`order`.comment, \n" + +// "\t`order`.account, \n" + +// "\t`order`.pwd, \n" + +// "\tcompany.`name` AS companyName, \n" + +// "\tplatform.`name` AS platformName\n" + +// "FROM\n" + +// "\tct_click_order AS `order`\n" + +// "\tLEFT JOIN\n" + +// "\tct_platform AS platform\n" + +// "\tON \n" + +// "\t\t`order`.platform_id = platform.id\n" + +// "\tLEFT JOIN\n" + +// "\tct_company AS company\n" + +// "\tON \n" + +// "\t\t`order`.company_id = company.id ${ew.customSqlSegment} ") + @Select("SELECT clickOrder.company_id, clickOrder.type, clickOrder.status, clickOrder.id, clickOrder.created_at, clickOrder.updated_at, clickOrder.amount, clickOrder.shop, clickOrder.order_id, clickOrder.comment, company.name AS companyName FROM ct_click_order AS clickOrder LEFT JOIN ct_company AS company ON clickOrder.company_id = company.id ${ew.customSqlSegment}") + IPage searchPageList(IPage page, Wrapper ew); + + @Select("SELECT\n" + + "\tclickOrder.id,\n" + + "\tclickOrder.order_id,\n" + + "\tclickOrder.COMMENT,\n" + + "\tclickOrder.STATUS,\n" + + "\tclickOrder.paths,\n" + + "\tbuyer.country,\n" + + "\tbuyer.account,\n" + + "\tbuyer.pwd,\n" + + "\tctVpn.link as vpnShare\n" + + "FROM\n" + + "\tct_click_order clickOrder\n" + + "\tLEFT JOIN ct_click_farming clickFarming ON clickOrder.id = clickFarming.ct_click_order_id \n" + + "\tLEFT JOIN ct_buyer buyer ON buyer.id = clickFarming.buyer_id\n" + + "\tLEFT JOIN ct_vpn ctVpn ON buyer.vpn_id = ctVpn.id\n" + + "WHERE \n" + + "\tclickOrder.id = #{orderId}") + CtClickFarmingOrderInfo getClickFarmOrderById(Long orderId); + + @Select("select * from ct_click_order where id = #{id} for update") + CtClickOrder getByIdLock(Long id); + + @Select("SELECT\n" + + "\tclickOrder.id,\n" + + "\tclickOrder.created_at,\n" + + "\tclickOrder.updated_at,\n" + + "\tclickOrder.prices_number,\n" + + "\tclickOrder.payment_results,\n" + + "\tclickOrder.order_id,\n" + + "\tclickOrder.COMMENT,\n" + +// "\tclickOrder.status,\n" + +// "\tclickOrder.platform_id,\n" + + "\tclickOrder.company_id,\n" + + "\tclickOrder.amount,\n" + + "\tclickOrder.shop,\n" + + "\tclickOrder.shop_name,\n" + + "\tclickOrder.order_date,\n" + + "\tclickOrder.paths\n" + + "FROM\n" + + "\tct_click_order clickOrder\n" + + "\tLEFT JOIN ct_click_farming clickFarming ON clickOrder.id = clickFarming.ct_click_order_id \n" + + "WHERE\n" + + "\tclickOrder.id = #{orderId}") + CtClickOrderDetailVO getClickOrderDetailById(Long id); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/CtCompanyDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/CtCompanyDao.java new file mode 100644 index 0000000..a5ff0de --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/CtCompanyDao.java @@ -0,0 +1,34 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import me.zhengjie.entity.CtCompany; +import me.zhengjie.entity.CtCompanyInfo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * 公司信息(CtCompany)表数据库访问层 + * + * @author zhw + * @since 2022-07-14 + */ +@Mapper +public interface CtCompanyDao extends BaseMapper { + + @Select({ + "" + }) + List getByName(@Param("names") List names); + + @Select("select id,name from ct_company") + List getCompanyList(); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/CtDhPayDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/CtDhPayDao.java new file mode 100644 index 0000000..3bc6536 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/CtDhPayDao.java @@ -0,0 +1,24 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import me.zhengjie.entity.CtDhPay; +import me.zhengjie.service.vo.CtBuyerListVO; +import me.zhengjie.service.vo.CtDhPayListVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +/** + * 平台信息(CtDyPay)表数据库访问层 + * + * @author rch + * @since 2022-07-28 + */ +@Mapper +public interface CtDhPayDao extends BaseMapper { + + @Select("select * from ct_dh_pay ${ew.customSqlSegment}") + IPage searchPageList(IPage page, Wrapper ew); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/CtExcelDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/CtExcelDao.java new file mode 100644 index 0000000..1291b82 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/CtExcelDao.java @@ -0,0 +1,17 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import me.zhengjie.entity.CtExcel; +import org.apache.ibatis.annotations.Mapper; + +/** + * Excel 导入信息(CtExcel)表数据库访问层 + * + * @author makejava + * @since 2022-06-23 10:37:44 + */ +@Mapper +public interface CtExcelDao extends BaseMapper { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/CtExcelImportInfoDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/CtExcelImportInfoDao.java new file mode 100644 index 0000000..94f2f76 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/CtExcelImportInfoDao.java @@ -0,0 +1,17 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import me.zhengjie.entity.CtExcelImportInfo; +import org.apache.ibatis.annotations.Mapper; + +/** + * Excel导入信息(CtExcelImportInfo)表数据库访问层 + * + * @author rch + * @since 2022-06-23 + */ +@Mapper +public interface CtExcelImportInfoDao extends BaseMapper { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/CtOrderDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/CtOrderDao.java new file mode 100644 index 0000000..c20f9da --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/CtOrderDao.java @@ -0,0 +1,17 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import me.zhengjie.entity.CtOrder; +import org.apache.ibatis.annotations.Mapper; + +/** + * (CtOrder)表数据库访问层 + * + * @author rch + * @since 2022-07-01 + */ +@Mapper +public interface CtOrderDao extends BaseMapper { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/CtPlatformDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/CtPlatformDao.java new file mode 100644 index 0000000..486b02c --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/CtPlatformDao.java @@ -0,0 +1,17 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import me.zhengjie.entity.CtPlatform; +import org.apache.ibatis.annotations.Mapper; + +/** + * 平台信息(CtPlatform)表数据库访问层 + * + * @author rch + * @since 2022-06-23 10:37:44 + */ +@Mapper +public interface CtPlatformDao extends BaseMapper { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/CtRebotDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/CtRebotDao.java new file mode 100644 index 0000000..589314c --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/CtRebotDao.java @@ -0,0 +1,41 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import me.zhengjie.base.BaseEntity; +import me.zhengjie.entity.CtRebot; +import me.zhengjie.service.vo.CtRebotListVO; +import me.zhengjie.utils.PageUtils; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; + +import java.util.List; + +/** + * 影刀设备-机器人信息(CtRebot)表数据库访问层 + * + * @author rch + * @since 2022-07-23 + */ +@Mapper +public interface CtRebotDao extends BaseMapper { + + @Select("select * from ct_rebot where account_name = #{accountName} for update") + CtRebot getByAccountNameLock(String accountName); + + + @Select("select * from ct_rebot ${ew.customSqlSegment}") + IPage searchRebotList(IPage page, Wrapper ew); + + @Select("select account_name from ct_rebot") + List getAccountNameList(); + + @Select("select robot_client_uuid from ct_rebot") + List getClientUuidList(); + + @Update("update ct_rebot set status = #{newStatus} where id = #{id} and status = #{oldStatus}") + Boolean updateNewStatusByOldStatus(Long id, Integer newStatus, Integer oldStatus); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/CtResponseOrderAddressDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/CtResponseOrderAddressDao.java new file mode 100644 index 0000000..e2195fb --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/CtResponseOrderAddressDao.java @@ -0,0 +1,17 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import me.zhengjie.entity.CtResponseOrderAddress; +import org.apache.ibatis.annotations.Mapper; + +/** + * 下注成功订单响应收货地址信息(CtResponseOrderAddress)表数据库访问层 + * + * @author rch + * @since 2022-07-01 + */ +@Mapper +public interface CtResponseOrderAddressDao extends BaseMapper { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/CtResponseOrderDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/CtResponseOrderDao.java new file mode 100644 index 0000000..5824efb --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/CtResponseOrderDao.java @@ -0,0 +1,17 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import me.zhengjie.entity.CtResponseOrder; +import org.apache.ibatis.annotations.Mapper; + +/** + * 下单成功响应订单商品信息(CtResponseOrder)表数据库访问层 + * + * @author rch + * @since 2022-07-01 + */ +@Mapper +public interface CtResponseOrderDao extends BaseMapper { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/CtResponseOrderProductDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/CtResponseOrderProductDao.java new file mode 100644 index 0000000..0ff58c8 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/CtResponseOrderProductDao.java @@ -0,0 +1,17 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import me.zhengjie.entity.CtResponseOrderProduct; +import org.apache.ibatis.annotations.Mapper; + +/** + * 下单订单响应产品信息(CtResponseOrderProduct)表数据库访问层 + * + * @author rch + * @since 2022-07-01 + */ +@Mapper +public interface CtResponseOrderProductDao extends BaseMapper { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/CtVpnDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/CtVpnDao.java new file mode 100644 index 0000000..7d0aa3e --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/CtVpnDao.java @@ -0,0 +1,35 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import me.zhengjie.entity.CtVpn; +import me.zhengjie.entity.CtVpnInfo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * VPN信息表(CtVpn)表数据库访问层 + * + * @author rch + * @since 2022-07-07 + */ +@Mapper +public interface CtVpnDao extends BaseMapper { + + @Select("select ip_address from ct_vpn") + List getIpList(); + + //@Select("select id,ip_address from ct_vpn where ip_address in ${ipAddress}") + @Select({ + "" + }) + List getVpnInfoByIp(List ipAddress); + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/DhAddCarDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/DhAddCarDao.java new file mode 100644 index 0000000..89e96ba --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/DhAddCarDao.java @@ -0,0 +1,61 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import me.zhengjie.entity.DhAddCar; +import me.zhengjie.service.vo.dhaddcar.DhAddCarVO; +import me.zhengjie.service.vo.dhaddcar.DhAddCarListVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +/** + * 敦煌加入购物车(DhAddCar)表数据库访问层 + * + * @author rch + * @since 2022-11-17 09:11:53 + */ +@Mapper +public interface DhAddCarDao extends BaseMapper { + + @Select("SELECT\n" + + "\tdhAddCar.*,\n" + + "\tbuyer.id AS buyerId,\n" + + "\tbuyer.account,\n" + + "\tbuyer.contntry_short AS country,\n" + + "\tcompany.NAME AS companyName\n" + + "\t\n" + + "FROM\n" + + "\tdh_add_car AS dhAddCar\n" + + "LEFT JOIN\n" + + "\tct_buyer buyer ON dhAddCar.buyer_id = buyer.id\n" + + "LEFT JOIN\n" + + "\tct_company company ON buyer.company_id = company.id\n" + + "\t${ew.customSqlSegment}") + IPage searchPageList(IPage page, Wrapper ew); + + + @Select("SELECT\n" + + " dhAddCar.id,\n" + + "\tdhAddCar.params_type,\n" + + "\tdhAddCar.car_good_ids AS carGoodIds,\n" + + "\tbuyer.id AS buyerId,\n" + + "\tbuyer.account,\n" + + "\tbuyer.contntry_short as country,\n" + + "\tbuyer.pwd,\n" + + "\tvpn.link as vpnShare,\n" + + "\tdhAddCar.status,\n" + + "\tcompany.NAME AS companyName\n" + + "FROM\n" + + "\tdh_add_car AS dhAddCar\n" + + "\tLEFT JOIN ct_buyer buyer ON dhAddCar.buyer_id = buyer.id\n" + + "\tLEFT JOIN ct_vpn vpn ON buyer.vpn_id = vpn.id\n" + + "\tLEFT JOIN\n" + + "\tct_company company ON buyer.company_id = company.id\n" + + "\tWHERE dhAddCar.id = #{id}") + DhAddCarVO getDetailById(Long id); + + @Select("select * from dh_add_car where id = #{id}") + DhAddCar getByIdLock(Long id); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/DhAddCarOrderDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/DhAddCarOrderDao.java new file mode 100644 index 0000000..c103c95 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/DhAddCarOrderDao.java @@ -0,0 +1,48 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import me.zhengjie.entity.DhAddCarOrder; +import me.zhengjie.service.vo.dhaddcar.DhAddCarListVO; +import me.zhengjie.service.vo.dhcarorder.DhAddCarOrderListVO; +import me.zhengjie.service.vo.dhcarorder.DhCarOrderParamsVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +/** + * 敦煌-加购物车-订单(DhAddCarOrder)表数据库访问层 + * + * @author rch + * @since 2022-11-17 09:11:57 + */ +@Mapper +public interface DhAddCarOrderDao extends BaseMapper { + + @Select("select * from dh_add_car_order where id = #{id} for update") + DhAddCarOrder getByIdLock(Long id); + + @Select("select * from dh_add_car_order ${ew.customSqlSegment}") + IPage searchPageList(IPage page, Wrapper ew); + + @Select("SELECT\n" + + "\tdhAddCarOrder.id,\n" + + "\tdhAddCarOrder.order_id,\n" + + "\tdhAddCar.params_type,\n" + + "\tdhAddCar.car_good_ids AS carGoodIds,\n" + + "\tbuyer.id AS buyerId,\n" + + "\tbuyer.account,\n" + + "\tbuyer.contntry_short AS country,\n" + + "\tbuyer.pwd,\n" + + "\tvpn.link AS vpnShare\n" + + "FROM\n" + + "\tdh_add_car_order as dhAddCarOrder\n" + + "\tLEFT JOIN dh_add_car dhAddCar ON dhAddCar.id = dhAddCarOrder.add_car_id\n" + + "\tLEFT JOIN ct_buyer buyer ON dhAddCar.buyer_id = buyer.id\n" + + "\tLEFT JOIN ct_vpn vpn ON buyer.vpn_id = vpn.id\n" + + "\tLEFT JOIN ct_company company ON buyer.company_id = company.id \n" + + "WHERE\n" + + "\tdhAddCarOrder.id = #{id}") + DhCarOrderParamsVO getYdParams(Long id); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/DhCarGoodsDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/DhCarGoodsDao.java new file mode 100644 index 0000000..8aa8743 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/DhCarGoodsDao.java @@ -0,0 +1,17 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import me.zhengjie.entity.DhCarGoods; +import org.apache.ibatis.annotations.Mapper; + +/** + * 敦煌-加入购物车商品信息(DhCarGoods)表数据库访问层 + * + * @author makejava + * @since 2022-11-17 09:12:01 + */ +@Mapper +public interface DhCarGoodsDao extends BaseMapper { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/LoginIpDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/LoginIpDao.java new file mode 100644 index 0000000..0acee04 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/LoginIpDao.java @@ -0,0 +1,17 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import me.zhengjie.entity.LoginIp; +import org.apache.ibatis.annotations.Mapper; + +/** + * (LoginIp)表数据库访问层 + * + * @author zeng + * @since 2022-03-21 14:07:01 + */ +@Mapper +public interface LoginIpDao extends BaseMapper { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/SettingSiteDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/SettingSiteDao.java new file mode 100644 index 0000000..b4f548f --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/SettingSiteDao.java @@ -0,0 +1,17 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import me.zhengjie.entity.CtSettingSite; +import org.apache.ibatis.annotations.Mapper; + +/** + * 站点配置(CtSettingSite)表数据库访问层 + * + * @author rch + * @since 2021-11-23 + */ +@Mapper +public interface SettingSiteDao extends BaseMapper { + String getValueByKey(String key); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/SysQuartzJobDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/SysQuartzJobDao.java new file mode 100644 index 0000000..ca96b7c --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/SysQuartzJobDao.java @@ -0,0 +1,26 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import me.zhengjie.entity.SysQuartzJob; +import me.zhengjie.service.vo.SysQuartzJobListVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +/** + * 定时任务(SysQuartzJob)表数据库访问层 + * + * @author zhw + * @since 2022-07-21 + */ +@Mapper +public interface SysQuartzJobDao extends BaseMapper { + + @Select("select * from sys_quartz_job ${ew.customSqlSegment}") + IPage searchPageList(IPage page, Wrapper ew); + + @Select("select * from sys_quartz_job where task_num = #{taskNum}") + SysQuartzJob getByTaskNum(String taskNum); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/SysQuartzLogDao.java b/wjcy-common/src/main/java/me/zhengjie/dao/SysQuartzLogDao.java new file mode 100644 index 0000000..64b4ba5 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/SysQuartzLogDao.java @@ -0,0 +1,23 @@ +package me.zhengjie.dao; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import me.zhengjie.entity.SysQuartzLog; +import me.zhengjie.service.vo.SysQuartzLogListVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +/** + * 定时任务(SysQuartzLog)表数据库访问层 + * + * @author rch + * @since 2022-07-20 + */ +@Mapper +public interface SysQuartzLogDao extends BaseMapper { + + @Select("select * from sys_quartz_log ${ew.customSqlSegment} ") + IPage searchPageList(IPage page, Wrapper ew); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/dao/mapper/CtDhPayService.xml b/wjcy-common/src/main/java/me/zhengjie/dao/mapper/CtDhPayService.xml new file mode 100644 index 0000000..25a0430 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dao/mapper/CtDhPayService.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/dto/Dto.java b/wjcy-common/src/main/java/me/zhengjie/dto/Dto.java new file mode 100644 index 0000000..159b385 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dto/Dto.java @@ -0,0 +1,73 @@ +package me.zhengjie.dto; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.error.ErrorCodeEnum; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + *

+ * 请求结果通用数据结构 + *

+ * + * @author: zeng + * @since: 2020-07-01 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Slf4j +public class Dto implements Serializable { + + private int code; + + private String message; + + private T data; + + private Dto(Object data) { + this.code = 200; + this.message = "请求成功"; + this.data =(T) data; + } + + private Dto(int code, String message) { + this.code = code; + this.message = message; + } + + public Dto setData(String key, Object value) { + if (this.data == null) { + data = (T)new HashMap(16); + } + ((Map) data).put(key, value); + return this; + } + + public static Dto returnResult(Object data) { + return new Dto(data); + } + + public static Dto returnErrorResult(String message) { + return new Dto(-1, message); + } + + public static Dto getInstance(ErrorCodeEnum errorCodeEnum) { + log.error("---枚举类返回错误信息:--return error:" + errorCodeEnum.getDesc()); + return new Dto(errorCodeEnum.getCode(), errorCodeEnum.getDesc()); + } + + public boolean success(Dto dto){ + if (dto.getCode() == 200) { + return true; + } else { + return false; + } + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/dto/PageDTO.java b/wjcy-common/src/main/java/me/zhengjie/dto/PageDTO.java new file mode 100644 index 0000000..ed0fa84 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dto/PageDTO.java @@ -0,0 +1,49 @@ +package me.zhengjie.dto; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.Data; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * @Description 分页查询参数 + * @Date 2022-06-22 + * @Author rch + */ +@Data +public class PageDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 当前页码 */ + @Min(value = 1) + @NotNull + private Integer page; + /** 页面大小 */ + @Min(value = 1) + @NotNull + private Integer pageSize; + /** 排序字段 */ + private String sort; + /** 排序方式 asc/desc */ + private String order; + + /** 获取mysql limit 分页的起始位置 */ + public Integer getLimitStart() { + int i = (page-1)*pageSize; + return i > 0 ? i : 0; + } + + public IPage getiPage(){ + return new Page(page, pageSize); + } + + + public boolean isAsc() { + return "asc".equalsIgnoreCase(order); + } + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/dto/StatementAggregateDTO.java b/wjcy-common/src/main/java/me/zhengjie/dto/StatementAggregateDTO.java new file mode 100644 index 0000000..ba9bf10 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/dto/StatementAggregateDTO.java @@ -0,0 +1,38 @@ +package me.zhengjie.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.PageUtils; + +import java.util.List; + +/** + * 本页合计、总计DTO + * @author zeng + * @since 2021/10/11 19:37 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class StatementAggregateDTO { + + /** 列表 */ + private List list; + + /** 本页小计 */ + private T pageTotal; + + /** 总计 */ + private T aggregate; + + /** 总记录数 */ + private Long total; + + public StatementAggregateDTO(PageUtils pageUtils, T pageTotal, T aggregate) { + this.list = pageUtils.getList(); + this.pageTotal = pageTotal; + this.aggregate = aggregate; + this.total = pageUtils.getTotal(); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtApply.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtApply.java new file mode 100644 index 0000000..f09b9de --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtApply.java @@ -0,0 +1,73 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * 影刀应用信息(CtApply)表实体类 + * + * @author rch + * @since 2022-07-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel +public class CtApply extends Model { + + @TableId(value = "id", type = IdType.AUTO) + @ApiModelProperty(value = "id") + private Long id; + + @TableField(fill = FieldFill.INSERT) + @ApiModelProperty(value = "创建时间") + private String createdAt; + + @TableField(fill = FieldFill.INSERT_UPDATE) + @ApiModelProperty(value = "修改时间") + private String updatedAt; + + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + @ApiModelProperty(value = "操作人账号") + private String gmName; + + /** 应用名称 */ + @ApiModelProperty(value = "应用名称") + private String name; + + /** 任务名称 */ + @ApiModelProperty(value = "任务名称") + private String taskName; + + /** 方法名称 */ + @ApiModelProperty(value = "方法名称") + private String methodName; + + /** accessKeyId */ + @ApiModelProperty(value = "accessKeyId") + private String accessKeyId; + + /** accessKeySecret */ + @ApiModelProperty(value = "accessKeySecret") + private String accessKeySecret; + + /** 应用id */ + @ApiModelProperty(value = "应用id") + private String robotUuid; + + /** 备注 */ + @ApiModelProperty(value = "备注") + private String remark; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtBrowse.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtBrowse.java new file mode 100644 index 0000000..2a64547 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtBrowse.java @@ -0,0 +1,45 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 浏览收藏(CtBrowse)表实体类 + * + * @author rch + * @since 2022-11-04 09:45:31 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtBrowse extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 买家ID */ + private Long buyerId; + + /** 收藏链接 */ + private String linkUrl; + + /** 状态描述 */ + private String paymentResults; + + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 */ + private Integer status; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtBrowseYdParams.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtBrowseYdParams.java new file mode 100644 index 0000000..89f99a6 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtBrowseYdParams.java @@ -0,0 +1,33 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 浏览好评订单影刀参数 + * + * @author rch + * @since 2022-11-07 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtBrowseYdParams { + private Long id; + + /** 国家 */ + private String country; + + /** 账号 */ + private String account; + + /** 密码 */ + private String pwd; + + /** vpn分享链接 */ + private String vpnShare; + + /** 收藏链接 */ + private String linkUrl; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyer.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyer.java new file mode 100644 index 0000000..49ab741 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyer.java @@ -0,0 +1,103 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +/** + * 买家信息表(CtBuyer)表实体类 + * + * @author rch + * @since 2022-06-22 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtBuyer extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 昵称*/ + private String nickName; + /** 账号*/ + private String account; + /** 密码*/ + private String pwd; + /** 公司id */ + private Long companyId; + /** 平台id */ + private Integer platformId; + /** 平台名称 */ +// private String platformName; + + // TODO 导入需要的字段接着往下添加 + + /** 国家 */ + private String contntryShort; + /** 邮件 */ + private String email; + /** Email密码 */ + private String emailPwd; + /** VPN_ID(导入excel里包含) */ + private Long vpnId; + /** 信用卡ID */ + private Long cardId; + /** 用户等级(导入默认内部账号) 1.普通 2.精品 3.压力 4.内部账号 */ + private Integer level; + /** 占用状态 1.已占用 2.未占用 */ + private Integer occupyStatus; + /** 占用账户 */ + private String occupyAccount; + /** 账户余额 */ + private BigDecimal balance; + /** 账户购买总金额 */ + private BigDecimal buyTotalMoney; + /** mac */ + private String mac; + /** route_mac*/ + private String routeMac; + /** Cookies值 */ + private String cookies; + /** 过期时间 */ + private String expireDate; + /** 状态(导入默认正常) 1.待注册 2待验证 3.待完善 4.正常 5.异常 6.可用但已用 7.删除 */ + private Integer status; + + // ==================地址信息相关========================================begin + /** 地址1 */ + private String addressline1; + /** 国家 */ + private String country; + /** 州 */ + private String state; + /** 电话 */ + private String tel; + /** lastname */ + private String lastname; + /** 税号 */ + private String vatNumber; + /** 城市 */ + private String city; + /** 地址2 */ + private String addressline2; + /** firstname */ + private String firstname; + /** 邮政编码 */ + private String postalcode; + // ==================地址信息相关========================================end +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerClickSuccess.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerClickSuccess.java new file mode 100644 index 0000000..13f46d8 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerClickSuccess.java @@ -0,0 +1,19 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 统计买家刷单成功个数信息 + * + * @author rch + * @create 2022-10-10 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtBuyerClickSuccess { + private Long buyerId; + private Integer successCount; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerContactInfo.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerContactInfo.java new file mode 100644 index 0000000..a680207 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerContactInfo.java @@ -0,0 +1,45 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +/** + * 买家收款地址信息 + * + * @author rch + * @since 2022-07-18 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtBuyerContactInfo { + /** 地址1 */ + private String addressline1; + /** 国家 */ + private String country; + /** 州 */ + private String state; + /** 电话 */ + private String tel; + /** lastname */ + private String lastname; + /** 税号 */ + private String vatNumber; + /** 城市 */ + private String city; + /** 地址2 */ + private String addressline2; + /** firstname */ + private String firstname; + /** 邮政编码 */ + private String postalcode; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerExport.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerExport.java new file mode 100644 index 0000000..92efaa9 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerExport.java @@ -0,0 +1,71 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; + + +/** + * 买家信息(CtBuyer)表实体类 导出对象信息 + * @author zhw + * @since 2022-07-14 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtBuyerExport { + + + @ExcelExport(value = "昵称") + /** 昵称*/ + private String nickName; + /** 账号*/ + @ExcelExport(value = "账号") + private String account; + /** 密码*/ + @ExcelExport(value = "密码") + private String pwd; + /** 公司名称 */ + @ExcelExport(value = "公司名称") + private String companyName; + /** 平台名称 */ + @ExcelExport(value = "平台名称") + private String platformName; + /** 国家 */ + @ExcelExport(value = "所属国家") + private String contntryShort; + /** VPN_IP地址*/ + @ExcelExport(value = "VPN_IP地址") + private String vpnIp; + /** 信用卡卡号 */ + @ExcelExport(value = "信用卡卡号") + private String cardNumber; + /** 地址1 */ + @ExcelExport(value = "地址1") + private String addressline1; + /** 国家 */ + @ExcelExport(value = "国家") + private String country; + /** 州 */ + @ExcelExport(value = "州") + private String state; + /** 电话 */ + @ExcelExport(value = "电话") + private String tel; + /** lastname */ + @ExcelExport(value = "lastname") + private String lastname; + /** 城市 */ + @ExcelExport(value = "城市") + private String city; + /** firstname */ + @ExcelExport(value = "firstname") + private String firstname; + /** 邮政编码 */ + @ExcelExport(value = "邮政编码") + private String postalcode; + /** 异常信息 */ + @ExcelExport(value = "异常信息") + private String error; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerExportTemple.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerExportTemple.java new file mode 100644 index 0000000..c92d084 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerExportTemple.java @@ -0,0 +1,67 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; + + +/** + * 买家信息(CtBuyer)表实体类 导出excel模板 + * @author zhw + * @since 2022-07-18 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtBuyerExportTemple { + + @ExcelExport(value = "昵称") + /** 昵称*/ + private String nickName; + /** 账号*/ + @ExcelExport(value = "账号") + private String account; + /** 密码*/ + @ExcelExport(value = "密码") + private String pwd; + /** 公司名称 */ + @ExcelExport(value = "公司名称") + private String companyName; + /** 平台名称 */ + @ExcelExport(value = "平台名称") + private String platformName; + /** 国家 */ + @ExcelExport(value = "所属国家") + private String contntryShort; + /** VPN_IP地址*/ + @ExcelExport(value = "VPN_IP地址") + private String vpnIp; + /** 信用卡卡号 */ + @ExcelExport(value = "信用卡卡号") + private String cardNumber; + /** 地址1 */ + @ExcelExport(value = "地址1") + private String addressline1; + /** 国家 */ + @ExcelExport(value = "国家") + private String country; + /** 州 */ + @ExcelExport(value = "州") + private String state; + /** 电话 */ + @ExcelExport(value = "电话") + private String tel; + /** lastname */ + @ExcelExport(value = "lastname") + private String lastname; + /** 城市 */ + @ExcelExport(value = "城市") + private String city; + /** firstname */ + @ExcelExport(value = "firstname") + private String firstname; + /** 邮政编码 */ + @ExcelExport(value = "邮政编码") + private String postalcode; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerImport.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerImport.java new file mode 100644 index 0000000..742bbdb --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtBuyerImport.java @@ -0,0 +1,84 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelImport; + +/** + * Buyer信息(CtBuyer)表实体类 Import + * + * @author zhw + * @since 2022-07-14 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtBuyerImport { + + private int rowNum; + private String rowTips; + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + @ExcelImport(value = "昵称", required = true) + /** 昵称*/ + private String nickName; + /** 账号*/ + @ExcelImport(value = "账号", required = true, unique = true) + private String account; + /** 密码*/ + @ExcelImport(value = "密码", required = true) + private String pwd; + /** 公司名称 */ + @ExcelImport(value = "公司名称", required = true) + private String companyName; + /** 平台名称 */ + @ExcelImport(value = "平台名称", required = true) + private String platformName; + /** 国家 */ + @ExcelImport(value = "所属国家", required = true) + private String contntryShort; + /** VPN_IP地址*/ + @ExcelImport(value = "VPN_IP地址", required = true) + private String vpnIp; + /** 信用卡卡号 */ + @ExcelImport(value = "信用卡卡号") + private String cardNumber; + /** 地址1 */ + @ExcelImport(value = "地址1", required = true) + private String addressline1; + /** 国家 */ + @ExcelImport(value = "国家", required = true) + private String country; + /** 州 */ + @ExcelImport(value = "州", required = true) + private String state; + /** 电话 */ + @ExcelImport(value = "电话", required = true) + private String tel; + /** lastname */ + @ExcelImport(value = "lastname", required = true) + private String lastname; + /** 城市 */ + @ExcelImport(value = "城市", required = true) + private String city; + /** firstname */ + @ExcelImport(value = "firstname", required = true) + private String firstname; + /** 邮政编码 */ + @ExcelImport(value = "邮政编码", required = true) + private String postalcode; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtCard.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtCard.java new file mode 100644 index 0000000..777745f --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtCard.java @@ -0,0 +1,80 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * 信用卡信息(CtCard)表实体类 + * + * @author rch + * @since 2022-07-07 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtCard extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 父ID */ + private Long parentId; + /** 卡号 */ + private String number; +// /** PIN码 */ +// private String pinNumber; + /** 持卡人姓氏 */ + private String holderSurname; + /** 持卡人名称 */ + private String holderName; + /** 有效期 */ + private String termOfValidity; + /** 余额 */ + private BigDecimal balance; + /** 累计消费 */ + private BigDecimal sumConsume; + /** 开卡日期 */ + private Date openDate; + /** 所属国家 */ + private String contntryShort; + /** 信用卡类型 1.Payoneer 2.万事达虚拟卡 3.Visa信用卡 */ + private Integer type; + /** 所属厂商:1.AmzKeys 2.Airwallex */ + private Integer cardDealer; + /** 身份证号 */ + private String idNumber; + /** 省份 */ + private String province; + /** 城市 */ + private String country; + /** 地址 */ + private String address; + /** 手机号 */ + private String phone; + /** 邮箱 */ + private String email; + /** 登陆账号 */ + private String account; + /** 密码 */ + private String pwd; + /** 状态:1.正常、2.异常、3.已删除 */ + private Integer status; + /** 备注 */ + private String remarks; +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtCardExport.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtCardExport.java new file mode 100644 index 0000000..7ed9aae --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtCardExport.java @@ -0,0 +1,40 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; + +/** + * 信用卡信息(CtCard)表实体类 导出对象信息 + * + * @author rch + * @since 2022-07-07 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtCardExport extends Model { + /** 卡号 */ + @ExcelExport(value = "卡号") + private String number; +// /** PIN码 */ +// @ExcelExport(value = "PIN码") +// private String pinNumber; + /** 有效期 */ + @ExcelExport(value = "有效期") + private String termOfValidity; + /** 信用卡类型 1.Payoneer 2.万事达虚拟卡 3.Visa信用卡 */ + @ExcelExport(value = "信用卡类型", kv = "1-Payoneer;2-万事达虚拟卡;3-Visa信用卡") + private Integer type; + /** 所属厂商:1.AmzKeys 2.Airwallex */ + @ExcelExport(value = "所属厂商", kv = "1-AmzKeys;2-Airwallex") + private Integer cardDealer; + /** 状态:1.正常、2.异常、3.已删除 */ + @ExcelExport(value = "状态", kv = "1-正常;2-异常;3-已删除") + private Integer status; + /** 异常信息 */ + @ExcelExport(value = "异常信息") + private String error; +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtCardExportTemple.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtCardExportTemple.java new file mode 100644 index 0000000..45d23c8 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtCardExportTemple.java @@ -0,0 +1,46 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; + +/** + * 信用卡信息(CtCard)表实体类 导出模版对象信息 + * + * @author rch + * @since 2022-07-07 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtCardExportTemple extends Model { + /** 卡号 */ + @ExcelExport(value = "卡号") + private String number; + /** PIN码 */ +// @ExcelExport(value = "PIN码") +// private String pinNumber; + /** 密码 */ + @ExcelExport(value = "密码") + private String pwd; + /** 有效期 */ + @ExcelExport(value = "有效期(文本:yyyy-MM-dd)") + private String termOfValidity; + /** 信用卡类型 1.Payoneer 2.万事达虚拟卡 3.Visa信用卡 */ + @ExcelExport(value = "信用卡类型", kv = "1-Payoneer;2-万事达虚拟卡;3-Visa信用卡") + private Integer type; + /** 所属厂商:1.AmzKeys 2.Airwallex */ + @ExcelExport(value = "所属厂商", kv = "1-AmzKeys;2-Airwallex") + private Integer cardDealer; + /** 状态:1.正常、2.异常、3.已删除 */ + @ExcelExport(value = "状态", kv = "1-正常;2-异常;3-已删除") + private Integer status; + /** 持卡人姓氏 */ + @ExcelExport(value = "持卡人姓氏") + private String holderSurname; + /** 持卡人名称 */ + @ExcelExport(value = "持卡人名称") + private String holderName; +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtCardImport.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtCardImport.java new file mode 100644 index 0000000..16f2235 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtCardImport.java @@ -0,0 +1,96 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelImport; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * 信用卡信息(CtCard)表实体类 Import + * + * @author rch + * @since 2022-07-07 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtCardImport extends Model { + + /** Excel 行号 */ + private int rowNum; + + /** Excel 错误提示 */ + private String rowTips; + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 父ID */ + private Long parentId; + /** 卡号 */ + @ExcelImport(value = "卡号", required = true, unique = true) + private String number; +// /** PIN码 */ +// @ExcelImport(value = "PIN码", required = true, unique = true) +// private String pinNumber; + /** 持卡人姓氏 */ + @ExcelImport(value = "持卡人姓氏") + private String holderSurname; + /** 持卡人名称 */ + @ExcelImport(value = "持卡人名称") + private String holderName; + /** 有效期 */ + @ExcelImport(value = "有效期(文本:yyyy-MM-dd)", required = true) + private String termOfValidity; + /** 余额 */ + private BigDecimal balance; + /** 累计消费 */ + private BigDecimal sumConsume; + /** 开卡日期 */ + private Date openDate; + /** 所属国家 */ + private String contntryShort; + /** 信用卡类型 1.Payoneer 2.万事达虚拟卡 3.Visa信用卡 */ + @ExcelImport(value = "信用卡类型", kv = "1-Payoneer;2-万事达虚拟卡;3-Visa信用卡", required = true) + private Integer type; + /** 所属厂商:1.AmzKeys 2.Airwallex */ + @ExcelImport(value = "所属厂商", kv = "1-AmzKeys;2-Airwallex", required = true) + private Integer cardDealer; + /** 身份证号 */ + private String idNumber; + /** 省份 */ + private String province; + /** 城市 */ + private String country; + /** 地址 */ + private String address; + /** 手机号 */ + private String phone; + /** 邮箱 */ + private String email; + /** 登陆账号 */ + private String account; + /** 密码 */ + @ExcelImport(value = "密码") + private String pwd; + /** 状态:1.正常、2.异常、3.已删除 */ + @ExcelImport(value = "状态", kv = "1-正常;2-异常;3-已删除", required = true) + private Integer status; + /** 备注 */ + private String remarks; +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtCardInfo.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtCardInfo.java new file mode 100644 index 0000000..70d4443 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtCardInfo.java @@ -0,0 +1,22 @@ +package me.zhengjie.entity; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Card(CtCard)表实体类 + * + * @author zhw + * @since 2022-07-14 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtCardInfo { + /** id */ + private Long id; + /** 信用卡卡号 */ + private String number; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmSupplyMentYdParams.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmSupplyMentYdParams.java new file mode 100644 index 0000000..e700dee --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmSupplyMentYdParams.java @@ -0,0 +1,41 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 刷单补录 + * + * @author rch + * @since 2022-08-16 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtClickFarmSupplyMentYdParams { + + private Long id; + /** 刷单类型 */ + private Integer paramsType; + /** 国家 */ + private String country; + /** 账号 */ + private String account; + /** 密码 */ + private String pwd; + /** vpn分享链接 */ + private String vpnShare; + + /** item */ + private String item; + /** 有效期 */ + private String termOfValidity; + /** 信用卡持卡人名称 */ + private String cardName; + /** 信用卡卡号 */ + private String cardNumber; + /** 信用卡密码 */ + private String cardPwd; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmYdParams.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmYdParams.java new file mode 100644 index 0000000..489e5b1 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmYdParams.java @@ -0,0 +1,59 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; + +/** + * 刷单信息 影刀参数 + * + * @author rch + * @since 2022-08-16 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtClickFarmYdParams { + + private Long id; + /** 刷单类型 */ + private Integer paramsType; + /** 国家 */ + private String country; + /** 账号 */ + private String account; + /** 密码 */ + private String pwd; + /** 关键词 */ + private String keyWord; + /** 数量 */ + private Integer number; + /** 规格 */ + private String specification; + /** 颜色 */ + private String color; + /** item */ + private String item; + private String exchange; + /** 最小价格区间 */ + private String sectionMin; + /** 最大价格区间 */ + private String sectionMax; + /** vpn分享链接 */ + private String vpnShare; + /** 链接 */ + private String link; + /** 留言 */ + private String amessage; + /** 有效期 */ + private String termOfValidity; + /** 信用卡持卡人名称 */ + private String cardName; + /** 信用卡卡号 */ + private String cardNumber; + /** 信用卡密码 */ + private String cardPwd; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarming.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarming.java new file mode 100644 index 0000000..e46c75a --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarming.java @@ -0,0 +1,70 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 刷单Excel信息(CtClickFarming)表实体类 + * + * @author rch + * @since 2022-08-16 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtClickFarming extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 关联刷单订单ID */ + private Long ctClickOrderId; + /** 买家id */ + private Long buyerId; + /** 刷单类型 */ + private Integer paramsType; + /** 店铺名称 */ + private String shopName; + /** 关键词 */ + private String keyWord; + /** 标题 */ + private String title; + /** 链接 */ + private String link; + /** 数量 */ + private Integer number; + /** 规格 */ + private String specification; + /** 颜色 */ + private String color; + /** item */ + private String item; + /** 优惠劵 */ + private String exchange; + /** 最小价格区间 */ + private String sectionMin; + /** 最大价格区间 */ + private String sectionMax; + /** 执行结果 */ + private String response; + /** 支付订单ID */ + private String payOrderId; + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 */ + private Integer status; + /** 留言 */ + private String amessage; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmingExport.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmingExport.java new file mode 100644 index 0000000..d26f1cf --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmingExport.java @@ -0,0 +1,59 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; +import me.zhengjie.utils.excel.ExcelImport; + +/** + * 刷单信息信息(CtCard)表实体类 Import + * + * @author rch + * @since 2022-08-16 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtClickFarmingExport { + /** 国家 */ + @ExcelExport(value = "国家") + private String country; + /** 账号 */ + @ExcelExport(value = "账号") + private String account; + /** 密码 */ + @ExcelExport(value = "密码") + private String pwd; + /** 店铺名称 */ + @ExcelExport(value = "店铺名称") + private String shopName; + /** 关键词 */ + @ExcelExport(value = "关键词") + private String keyWord; + /** 标题 */ + @ExcelExport(value = "标题") + private String title; + /** 链接 */ + @ExcelExport(value = "链接") + private String link; + /** 数量 */ + @ExcelExport(value = "数量") + private Integer number; + /** 规格 */ + @ExcelExport(value = "规格") + private String specification; + /** 颜色 */ + @ExcelExport(value = "颜色") + private String color; + /** item */ + @ExcelExport(value = "item") + private String item; + /** vpn分享链接 */ + @ExcelExport(value = "vpn分享链接") + private String vpnShare; + /** 异常信息 */ + @ExcelExport(value = "异常信息") + private String error; +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmingExportTemp.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmingExportTemp.java new file mode 100644 index 0000000..2f3d623 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmingExportTemp.java @@ -0,0 +1,53 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; + +/** + * 刷单信息信息(CtCard)表实体类 Import + * + * @author rch + * @since 2022-08-16 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtClickFarmingExportTemp { + /** 账号 */ + @ExcelExport(value = "账号") + private String account; + /** 商品属性类型:1.关键词 2.链接 */ + @ExcelExport(value = "商品属性类型", kv = "1-关键词;2-链接") + private Integer paramsType; + /** 店铺名称 */ + @ExcelExport(value = "店铺名称") + private String shopName; + /** 关键词 */ + @ExcelExport(value = "关键词") + private String keyWord; + /** 标题 */ + @ExcelExport(value = "标题") + private String title; + /** 链接 */ + @ExcelExport(value = "链接") + private String link; + /** 数量 */ + @ExcelExport(value = "数量") + private Integer number; + /** 规格 */ + @ExcelExport(value = "规格") + private String specification; + /** 颜色 */ + @ExcelExport(value = "颜色") + private String color; + @ExcelExport(value = "优惠卷") + private String exchange; + /** 商品item */ + @ExcelExport(value = "商品item") + private String item; + /** 留言 */ + @ExcelExport(value = "留言") + private String amessage; +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmingImport.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmingImport.java new file mode 100644 index 0000000..2144533 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmingImport.java @@ -0,0 +1,64 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelImport; + +/** + * 刷单信息信息(CtCard)表实体类 Import + * + * @author rch + * @since 2022-08-16 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtClickFarmingImport { + + /** Excel 行号 */ + private int rowNum; + + /** Excel 错误提示 */ + private String rowTips; + + /** 买家id */ + private Long buyerId; + + /** 账号 */ + @ExcelImport(value = "账号", required = true, unique = true) + private String account; + /** 商品属性类型:1.关键词 2.链接 */ + @ExcelImport(value = "商品属性类型", kv = "1-关键词; 2-链接") + private Integer paramsType; + /** 店铺名称 */ + @ExcelImport(value = "店铺名称") + private String shopName; + /** 关键词 */ + @ExcelImport(value = "关键词") + private String keyWord; + /** 标题 */ + @ExcelImport(value = "标题") + private String title; + /** 链接 */ + @ExcelImport(value = "链接") + private String link; + /** 数量 */ + @ExcelImport(value = "数量") + private Integer number; + /** 规格 */ + @ExcelImport(value = "规格") + private String specification; + /** 颜色 */ + @ExcelImport(value = "颜色") + private String color; + /** item */ + @ExcelImport(value = "商品item") + private String item; + /** 优惠劵 */ + @ExcelImport(value = "优惠卷") + private String exchange; + /** 留言 */ + @ExcelImport(value = "留言", required = true) + private String amessage; +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmingOrderInfo.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmingOrderInfo.java new file mode 100644 index 0000000..280ca9c --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickFarmingOrderInfo.java @@ -0,0 +1,37 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 刷单订单信息详情(刷单信息+订单信息) + * + * @author rch + * @since 2022-08-16 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtClickFarmingOrderInfo { + + private Long id; + /** 国家 */ + private String country; + /** 账号 */ + private String account; + /** 密码 */ + private String pwd; + /** vpn分享链接 */ + private String vpnShare; + + /** 订单id */ + private String orderId; + /** 评论 */ + private String comment; + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 */ + private Integer status; + /** 图片地址 */ + private String paths; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrder.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrder.java new file mode 100644 index 0000000..9e1ed52 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrder.java @@ -0,0 +1,55 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 刷单-订单信息(CtClickOrder)表实体类 + * + * @author rch + * @since 2022-09-14 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtClickOrder extends Model { + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + /** 公司ID */ + private Long companyId; + /** 类型 1.导入 2.刷单*/ + private Integer type; + /** 总金额 */ + private String amount; + /** 状态描述 */ + private String paymentResults; + /** 店铺名称 */ + private String shop; + /** 购买数量 */ + private String pricesNumber; + /** 订单id */ + private String orderId; + /** 商品名称 */ + private String shopName; + /** 时间 */ + private String orderDate; + /** 评论 */ + private String comment; + /** 图片地址 */ + private String paths; + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 */ + private Integer status; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrderExport.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrderExport.java new file mode 100644 index 0000000..3e2935e --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrderExport.java @@ -0,0 +1,37 @@ +package me.zhengjie.entity; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; + +/** + * 刷单订单实体类 导出模版对象信息 + * + * @author rch + * @since 2022-09-27 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtClickOrderExport { + + /** 公司名称 */ + @ExcelExport(value = "公司名称") + private String companyName; + /** 总金额 */ + @ExcelExport(value = "总金额") + private String amount; + /** 店铺名称 */ + @ExcelExport(value = "店铺名称") + private String shop; + /** 订单id */ + @ExcelExport(value = "订单id") + private String orderId; + /** 评论 */ + @ExcelExport(value = "评论") + private String comment; + @ExcelExport(value = "异常信息") + private String error; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrderExportTemple.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrderExportTemple.java new file mode 100644 index 0000000..49e25f7 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrderExportTemple.java @@ -0,0 +1,39 @@ +package me.zhengjie.entity; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; +import me.zhengjie.utils.excel.ExcelImport; + +/** + * 刷单订单实体类 导出模版对象信息 + * + * @author rch + * @since 2022-09-27 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtClickOrderExportTemple { + + /** 平台名称 */ + @ExcelExport(value = "平台名称") + private Integer platformId; + /** 公司名称 */ + @ExcelExport(value = "公司名称") + private Long companyId; + /** 总金额 */ + @ExcelExport(value = "总金额") + private String amount; + /** 店铺名称 */ + @ExcelExport(value = "店铺名称") + private String shop; + /** 订单id */ + @ExcelExport(value = "订单id") + private String orderId; + /** 评论 */ + @ExcelExport(value = "评论") + private String comment; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrderImport.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrderImport.java new file mode 100644 index 0000000..a4695dc --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrderImport.java @@ -0,0 +1,40 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; +import me.zhengjie.utils.excel.ExcelImport; + +/** + * Vpn信息(CtVpn)表实体类 Import + * + * @author rch + * @since 2022-09-27 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtClickOrderImport { + private int rowNum; + + private String rowTips; + + /** 公司ID */ + private Long companyId; + /** 公司名称 */ + @ExcelImport(value = "公司名称", required = true) + private String companyName; + /** 总金额 */ + @ExcelImport(value = "总金额", required = true) + private String amount; + /** 店铺名称 */ + @ExcelImport(value = "店铺名称", required = true) + private String shop; + /** 订单id */ + @ExcelImport(value = "订单id", required = true) + private String orderId; + /** 评论 */ + @ExcelImport(value = "评论") + private String comment; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrderYdParams.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrderYdParams.java new file mode 100644 index 0000000..9a1b5e6 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtClickOrderYdParams.java @@ -0,0 +1,33 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 刷单订单影刀参数 + * + * @author rch + * @since 2022-10-21 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtClickOrderYdParams { + private Long id; + /** 国家 */ + private String country; + /** 账号 */ + private String account; + /** 密码 */ + private String pwd; + /** vpn分享链接 */ + private String vpnShare; + /** 订单id */ + private String orderId; + /** 评论 */ + private String comment; + /** 图片 */ + private String paths; + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtCompany.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtCompany.java new file mode 100644 index 0000000..eff48bf --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtCompany.java @@ -0,0 +1,43 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 公司信息(CtCompany)表实体类 + * + * @author rch + * @since 2022-06-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtCompany extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + /** 名称 */ + private String name; + /** 地址 */ + private String address; + /** 电话 */ + private String phone; + /** 商户码(公司调用api公司唯一标识) */ + private String number; + /** 商户token(公司调用api公司token身份标识) */ + private String token; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtCompanyInfo.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtCompanyInfo.java new file mode 100644 index 0000000..de0f007 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtCompanyInfo.java @@ -0,0 +1,23 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 公司信息(CtCompany)表实体类 + * + * @author zhw + * @since 2022-07-14 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtCompanyInfo { + + /** id */ + private Long id; + /** 名称 */ + private String name; + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtDhPay.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtDhPay.java new file mode 100644 index 0000000..222896e --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtDhPay.java @@ -0,0 +1,44 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * 平台信息(CtDyPay)表实体类 + * + * @author rch + * @since 2022-07-28 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtDhPay extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 买家名称 */ + private String buyerName; + /** 支付订单ID(敦煌的) */ + private String orderId; + /** 请求响应详情 */ + private String response; + /** 状态 0.待处理 1.支付成功 2.支付失败 */ + private Integer status; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtDhPayExport.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtDhPayExport.java new file mode 100644 index 0000000..3586977 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtDhPayExport.java @@ -0,0 +1,29 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; + +/** + * 敦煌支付信息(CtDhPay)表实体类 Export + * + * @author rch + * @since 2022-07-28 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtDhPayExport extends Model { + /** 买家名称 */ + @ExcelExport(value = "买家账号") + private String buyerName; + /** 支付订单ID(敦煌的) */ + @ExcelExport(value = "支付订单") + private String orderId; + + /** 异常信息 */ + @ExcelExport(value = "异常信息") + private String error; +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtDhPayExportTemple.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtDhPayExportTemple.java new file mode 100644 index 0000000..4f5614e --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtDhPayExportTemple.java @@ -0,0 +1,25 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; + +/** + * 敦煌支付信息(CtDhPay)表实体类 导出模版对象信息 + * + * @author rch + * @since 2022-07-28 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtDhPayExportTemple extends Model { + /** 买家名称 */ + @ExcelExport(value = "买家账号") + private String buyerName; + /** 支付订单ID(敦煌的) */ + @ExcelExport(value = "支付订单") + private String orderId; +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtDhPayImport.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtDhPayImport.java new file mode 100644 index 0000000..863019c --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtDhPayImport.java @@ -0,0 +1,40 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelImport; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * 敦煌支付信息(CtDhPay)表实体类 Import + * + * @author rch + * @since 2022-07-28 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtDhPayImport{ + + /** Excel 行号 */ + private int rowNum; + + /** Excel 错误提示 */ + private String rowTips; + + /** 买家名称 */ + @ExcelImport(value = "买家账号", required = true, unique = true) + private String buyerName; + + /** 支付订单ID(敦煌的) */ + @ExcelImport(value = "支付订单", required = true, unique = true) + private String orderId; +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtExcel.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtExcel.java new file mode 100644 index 0000000..4c9bef7 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtExcel.java @@ -0,0 +1,41 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Excel 导入信息(CtExcel)表实体类 + * + * @author rch + * @since 2022-06-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtExcel extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 备注 */ + private String remarks; + /** excel路径 */ + + private String path; + private String errorPath; + /** 状态 1.待导入 2.导入成功 3.导入失败 */ + private Integer status; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtExcelExportInfo.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtExcelExportInfo.java new file mode 100644 index 0000000..f9954c3 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtExcelExportInfo.java @@ -0,0 +1,40 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; + +/** + * Excel 导出信息(CtExcelImportInfo)表实体类 + * + * @author rch + * @since 2022-07-18 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtExcelExportInfo extends Model { + + /** 公司主键 */ + @ExcelExport("公司主键") + private Long companyId; + + /** 鉴权枚举 */ + @ExcelExport("鉴权枚举") + private Long tokenEnum; + + /** 订单来源 */ + @ExcelExport("订单来源") + private String fromDetailInfo; + + /** 产品信息-JSON */ + @ExcelExport("产品信息") + private String cartList; + + /** 异常信息 */ + @ExcelExport(value = "异常信息") + private String error; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtExcelExportTemple.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtExcelExportTemple.java new file mode 100644 index 0000000..cd9499b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtExcelExportTemple.java @@ -0,0 +1,33 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; + +/** + * EXCEL(CtExcel)表实体类 导出excel模板 + * @author zhw + * @since 2022-07-18 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtExcelExportTemple { + + /** 公司主键 */ + @ExcelExport("公司主键") + private Long companyId; + + /** 鉴权枚举 */ + @ExcelExport("鉴权枚举") + private Long tokenEnum; + + /** 订单来源 */ + @ExcelExport("订单来源") + private String fromDetailInfo; + + /** 产品信息-JSON */ + @ExcelExport("产品信息") + private String cartList; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtExcelImportInfo.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtExcelImportInfo.java new file mode 100644 index 0000000..153b8ca --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtExcelImportInfo.java @@ -0,0 +1,59 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelImport; + +/** + * Excel导入信息(CtExcelImportInfo)表实体类 + * + * @author rch + * @since 2022-06-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtExcelImportInfo extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 公司主键 */ + @ExcelImport("公司主键") + private Long companyId; + + /** 鉴权枚举 */ + @ExcelImport("鉴权枚举") + private Long tokenEnum; + + /** 订单来源 */ + @ExcelImport("订单来源") + private String fromDetailInfo; + + /** 产品信息-JSON */ + @ExcelImport("产品信息") + private String cartList; + + /** 订单收货地址-JSON */ + private String contactInfo; + + /** 我们平台订单编号 */ + private String orderNo; + + /** 状态 1.待处理 2.处理成功 3.处理失败 */ + private Integer status; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtOrder.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtOrder.java new file mode 100644 index 0000000..8117c8b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtOrder.java @@ -0,0 +1,55 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * (CtOrder)表实体类 + * + * @author rch + * @since 2022-06-30 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtOrder extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + + /** 公司Id */ + private Long companyId; + /** ExcelId 信息 */ + private Long excelInfoId; + /** 买家ID */ + private Long buyerId; + /** 买家buy_access_token */ + private String buyAccessToken; + /** 我们平台订单编号 */ + private String ctOrderNo; + /** 订单号,下单成功响应的订单号(冗余字段 下单成功响应订单信息里有) */ + private Long orderNo; + /** 下单成功响应的产品id( a,b,c 格式) (响应字段很多,先少些几个) */ + private Long responseProductId; + /** 下单成功响应的订单地址id(响应字段很多,先少些几个) */ + private Long responseOrderAddressId; + /** 下单成功响应的订单信息 (响应字段很多,先少些几个) */ + private Long responseOrderId; + /** 响应码信息 */ + private String orderResponseStatus; + /** 响应码信息 */ + private String payResponseStatus; + /** 状态 1.待支付(下单成功) 2.支付成功 3.支付失败*/ + private Integer status; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtParamContactInfo.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtParamContactInfo.java new file mode 100644 index 0000000..2feb27c --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtParamContactInfo.java @@ -0,0 +1,39 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 下单API请求参数订单收货地址信息 + * + * @author rch + * @since 2022-06-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtParamContactInfo { + /** 必须 所在国家; 示例值:US 所在国家 */ + private String country; + /** 必须 收货人lastname ;示例值:zhao 收货人firstname */ + private String firstname; + /** 必须 收货人联系电话,固定电话或者移动电话 ;示例值:1311111111 收货人联系电话,固定电话或者移动电话 */ + private String tel; + /** 否 收货人地址1 ;示例值:chengfulu road, hawio 收货人地址2 */ + private String addressline2; + /** 必须 所在州 ;示例值:California 所在州 */ + private String state; + /** 必须 所在城市; 示例值:Chicago 所在城市 */ + private String city; + /** 必须 收货人地址1 ;示例值:chengfulu road, hawio 收货人地址1 */ + private String addressline1; + /** 必须 地址邮编 ;示例值:12345 地址邮编 */ + private String postalcode; + /** 必须 收货人lastname ;示例值:yiyi 收货人lastname */ + private String lastname; + /** 否 税号:BR,AR,EC,AO,LB,TR,KR必填 税号 */ + private String vatNumber; + /** 否 Email地址 ;示例值:zhaoyiyi@163.com Email地址 */ + private String email; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtParamProduct.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtParamProduct.java new file mode 100644 index 0000000..0a8a937 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtParamProduct.java @@ -0,0 +1,29 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 下单Api请求产品信息参数实体类 + * + * @author rch + * @since 2022-06-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtParamProduct { + /** 必须 产品购买数量 示例值:2 产品数量 */ + private Integer quantity; + /** 否 可以从获取商品运费详情API获取expressType字段(分销API>物流API>dh.dropshipping.ship.get$1.0);示例值:ePacket 物流方式 */ + private String shipType; + /** 否 可根据国家字典查询国家详情(dh.base.countrys.get$1.0); 示例值:CN;默认值:CN 备货国家ID */ + private String stockin; + /** 否 站点 站点 */ + private String siteId; + /** 必须 产品itemcode ;示例值:634706114 产品编码 */ + private Long itemcode; + /** 必须 产品skuMd5,可以从商品详情API获取(分析API>商品API>dh.dropshipping.item.get$1.0) ;示例值:562e86410bd37a7bb4170cfe6e03203f 产品skuMd5 */ + private String skuMd5; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtPlatform.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtPlatform.java new file mode 100644 index 0000000..81ba872 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtPlatform.java @@ -0,0 +1,40 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 平台信息(CtPlatform)表实体类 + * + * @author rch + * @since 2022-06-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtPlatform extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 名称 */ + private String name; + /** 地址 */ + private String address; + /** 电话 */ + private String phone; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtRebot.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtRebot.java new file mode 100644 index 0000000..9c6371d --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtRebot.java @@ -0,0 +1,41 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * 影刀设备-机器人信息(CtRebot)表实体类 + * + * @author rch + * @since 2022-07-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtRebot extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 机器人账号 */ + private String accountName; + /** 机器人Uuid信息 */ + private String robotClientUuid; + /** 状态 0.未占用 1.占用 */ + private Integer status; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtRebotExport.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtRebotExport.java new file mode 100644 index 0000000..c486f3b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtRebotExport.java @@ -0,0 +1,31 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; +import me.zhengjie.utils.excel.ExcelImport; + +/** + * 影刀机器人信息(ct_rebot) 导出 + * + * @Author zhw + * @Date 2022-07-25 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtRebotExport { + /** 机器人账号 */ + @ExcelExport(value = "机器人账号") + private String accountName; + /** 机器人Uuid信息 */ + @ExcelExport(value = "Uuid信息") + private String robotClientUuid; + @ExcelExport(value = "异常信息") + private String error; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtRebotExportTemple.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtRebotExportTemple.java new file mode 100644 index 0000000..d7c80f7 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtRebotExportTemple.java @@ -0,0 +1,24 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; + +/** + * 机器人模板EXCEL导出(ct_rebot) + * + * @Author zhw + * @Date 2022-07-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtRebotExportTemple { + /** 机器人账号 */ + @ExcelExport(value = "机器人账号") + private String accountName; + /** 机器人Uuid信息 */ + @ExcelExport(value = "Uuid信息") + private String robotClientUuid; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtRebotImport.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtRebotImport.java new file mode 100644 index 0000000..54fe190 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtRebotImport.java @@ -0,0 +1,43 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelImport; + +/** + * 影刀机器人信息(ct_rebot) import + * + * @Author zhw + * @Date 2022-07-25 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtRebotImport { + + private int romNum; + private String rowTips; + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 机器人账号 */ + @ExcelImport(value = "机器人账号", required = true) + private String accountName; + /** 机器人Uuid信息 */ + @ExcelImport(value = "Uuid信息", required = true) + private String robotClientUuid; + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtResponseOrder.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtResponseOrder.java new file mode 100644 index 0000000..9d2e35f --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtResponseOrder.java @@ -0,0 +1,67 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * 下单成功响应订单商品信息(CtResponseOrder)表实体类 + * + * @author rch + * @since 2022-06-30 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtResponseOrder extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 运费 */ + private Double shipCost; + /** 产品总价 */ + private Double totalPriceOfProduct; + /** 备货期 */ + private Double leadingTime; + /** 订单总价 */ + private Double orderTotal; + /** 卖家Id */ + private String supplierId; + /** 卖家店铺coupon */ + private Double couponOfSeller; + /** 运输方式 */ + private String shipType; + /** 订单优惠 */ + private Double orderSave; + /** 税费手续费 */ + private Double taxCharge; + /** 买家Id */ + private String buyerId; + /** 税费 */ + private Double tax; + /** 促销折扣 */ + private Double promoDiscount; + /** 订单号--这个要特殊处理这个是对应响应的id字段 */ + private Long orderId; + /** DHcoupon */ + private Double couponDiscount; + /** 下单站点 */ + private String siteId; + /** 创建时间 */ + private Date createTime; +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtResponseOrderAddress.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtResponseOrderAddress.java new file mode 100644 index 0000000..cfecf60 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtResponseOrderAddress.java @@ -0,0 +1,53 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 下注成功订单响应收货地址信息(CtResponseOrderAddress)表实体类 + * + * @author rch + * @since 2022-06-30 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtResponseOrderAddress extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 地址1 */ + private String addressline1; + /** 国家 */ + private String country; + /** 州 */ + private String state; + /** 电话 */ + private String tel; + /** lastname */ + private String lastname; + /** 税号 */ + private String vatNumber; + /** 城市 */ + private String city; + /** 地址2 */ + private String addressline2; + /** firstname */ + private String firstname; + /** 邮政编码 */ + private String postalcode; +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtResponseOrderProduct.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtResponseOrderProduct.java new file mode 100644 index 0000000..9682b76 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtResponseOrderProduct.java @@ -0,0 +1,96 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * 下单订单响应产品信息(CtResponseOrderProduct)表实体类 + * + * @author rch + * @since 2022-06-30 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtResponseOrderProduct extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 秒杀类型 */ + private String flashDeals; + /** 卖家设置价格 */ + private Double prodPriceOrg; + /** 产品skuId */ + private String skuId; + /** 购买数量 */ + private Integer cateDispId; + /** 商品总金额 */ + private Double amount; + /** 发布类目id */ + private String catePubId; + /** 促销折扣 */ + private Double promDis; + /** 产品单位名称 */ + private String measureName; + /** 短描 */ + private String shortDescription; + /** 卖家承诺运达天数 */ + private Integer promiseDays; + /** 备货国家 */ + private String stockin; + /** 产品图片(小图) */ + private String thumbnailImage; + /** 是否为样品 */ + private String isSample; + /** 最终运费 */ + private Double shipCost; + /** 卖家Id */ + private String supplierId; + /** 跨店满减金额 */ + private BigDecimal crossReduceAmount; + /** 产品itemcode */ + private Integer itemcode; + /** buyer选择的运输方式 */ + private String shipType; + /** 销售价格 */ + private Double originPrice; + /** 产品长描地址 */ + private String htmlUrl; + /** 产品图片(大图) */ + private String imageUrl; + /** 最终价格 */ + private Double price; + /** 产品URL */ + private String productUrl; + /** 备注 */ + private String remark; + /** lots */ + private Integer lots; + /** 产品名称 */ + private String productName; + /** 产品Id */ + private String productId; + /** 产品skumd5 */ + private String skuMd5; + /** 创建时间 */ + private Date createTime; + /** 产品单位Id */ + private String measureId; +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtSettingSite.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtSettingSite.java new file mode 100644 index 0000000..a2209ea --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtSettingSite.java @@ -0,0 +1,43 @@ +package me.zhengjie.entity; + + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 站点配置(CtSettingSite)表实体类 + * + * @author rch + * @since 2022-06-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtSettingSite extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 设置KEY */ + private String settingKey; + /** 设置value */ + private String settingValue; + /** 中文描述 */ + private String content; + /** 单位 */ + private String unit; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtVpn.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtVpn.java new file mode 100644 index 0000000..7e613ab --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtVpn.java @@ -0,0 +1,55 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * VPN信息表(CtVpn)表实体类 + * + * @author rch + * @since 2022-07-07 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtVpn extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 所属国家简称 */ + private String contntryShort; + /** IP地址 */ + private String ipAddress; + /** 父ip地址 */ + private String parentIpAddress; + /** 端口 */ + private Integer port; + /** 名称 */ + private String name; + /** 密码 */ + private String pwd; + /** VPS类型 1.传统 */ + private Integer vpsType; + /** 经销商 1.V2 */ + private Integer dealer; + /** mac地址 */ + private String mac; + /** 链接 */ + private String link; + /** 经销商 1.可用 2.禁用 */ + private Integer status; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtVpnExport.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtVpnExport.java new file mode 100644 index 0000000..cff274d --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtVpnExport.java @@ -0,0 +1,45 @@ +package me.zhengjie.entity; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; + +/** + * Vpn信息(CtCard)表实体类 export + * + * @author zhw + * @since 2022-07-13 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtVpnExport { + + /** 所属国家简称 */ + @ExcelExport(value = "所属国家简称") + private String contntryShort; + /** IP地址 */ + @ExcelExport(value = "IP地址") + private String ipAddress; + @ExcelExport(value = "端口") + private Integer port; + /** 名称 */ + @ExcelExport(value = "名称") + private String name; + /** 密码 */ + @ExcelExport(value = "密码") + private String pwd; + /** VPS类型 1.传统 */ + @ExcelExport(value = "VPS类型", kv = "1-传统") + private Integer vpsType; + /** 经销商 1.V2 */ + @ExcelExport(value = "经销商", kv = "1-V2") + private Integer dealer; + @ExcelExport(value = "链接") + private String link; + @ExcelExport(value = "异常信息") + private String error; + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtVpnExportTemple.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtVpnExportTemple.java new file mode 100644 index 0000000..1e3bca1 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtVpnExportTemple.java @@ -0,0 +1,43 @@ +package me.zhengjie.entity; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; + +/** + * Vpn信息(CtVpn)表实体类 导出模版对象信息 + * + * @author zhw + * @since 2022-07-13 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtVpnExportTemple { + + /** 所属国家简称 */ + @ExcelExport(value = "所属国家简称", example = "中国") + private String contntryShort; + /** IP地址 */ + @ExcelExport(value = "IP地址", example = "192.0.0.1") + private String ipAddress; + @ExcelExport(value = "端口", example = "8088") + private Integer port; + /** 名称 */ + @ExcelExport(value = "名称", example = "示例") + private String name; + /** 密码 */ + @ExcelExport(value = "密码", example = "123123") + private String pwd; + /** VPS类型 1.传统 */ + @ExcelExport(value = "VPS类型", kv = "1-传统", example = "传统") + private Integer vpsType; + @ExcelExport(value = "链接", example = "vmess://ew0KICAidiI6ICIyIiwNCiAgInBzIjogIjEwNC4yMjEuMTk5LjgyIiwNCiAgImFkZCI6ICJ1cy1lczM0LmZvYmhlbHAuY29tIiwNCiAgInBvcnQiOiAiMzAwNDMiLA0KICAiaWQiOiAiYzA4NDk5ODQtZWNjNC01MzY3LTlmOTctYTI2ODljNTQ5N2QyIiwNCiAgImFpZCI6ICI2NCIsDQogICJzY3kiOiAiYXV0byIsDQogICJuZXQiOiAidGNwIiwNCiAgInR5cGUiOiAibm9uZSIsDQogICJob3N0IjogIiIsDQogICJwYXRoIjogIiIsDQogICJ0bHMiOiAiIiwNCiAgInNuaSI6ICIiDQp9") + private String link; + /** 经销商 1.V2 */ + @ExcelExport(value = "经销商", kv = "1-V2", example = "V2") + private Integer dealer; + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtVpnImport.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtVpnImport.java new file mode 100644 index 0000000..e1cb352 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtVpnImport.java @@ -0,0 +1,66 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelImport; + +/** + * Vpn信息(CtVpn)表实体类 Import + * + * @author zhw + * @since 2022-07-13 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtVpnImport { + private int rowNum; + + private String rowTips; + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 所属国家简称 */ + @ExcelImport(value = "所属国家简称", required = true) + private String contntryShort; + /** IP地址 */ + @ExcelImport(value = "IP地址", required = true, unique = true) + private String ipAddress; + /** 父ip地址 */ + private String parentIpAddress; + /** 端口 */ + @ExcelImport(value = "端口", required = true) + private Integer port; + /** 名称 */ + @ExcelImport(value = "名称", required = true) + private String name; + /** 密码 */ + @ExcelImport(value = "密码", required = true) + private String pwd; + /** VPS类型 1.传统 */ + @ExcelImport(value = "VPS类型", kv = "1-传统", required = true) + private Integer vpsType; + /** 经销商 1.V2 */ + @ExcelImport(value = "经销商", kv = "1-V2", required = true) + private Integer dealer; + /** mac地址 */ + private String mac; + /** 链接 */ + @ExcelImport(value = "链接", required = true, maxLength = 2000) + private String link; + /** 状态 1.可用 2.禁用 */ + private Integer status; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/CtVpnInfo.java b/wjcy-common/src/main/java/me/zhengjie/entity/CtVpnInfo.java new file mode 100644 index 0000000..2fd174b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/CtVpnInfo.java @@ -0,0 +1,23 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + + +/** + * Vpn(CtVpn)表实体类 + * + * @author zhw + * @since 2022-07-14 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtVpnInfo { + + /** id */ + private Long id; + /** Ip地址 */ + private String ipAddress; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/DhAddCar.java b/wjcy-common/src/main/java/me/zhengjie/entity/DhAddCar.java new file mode 100644 index 0000000..a0e2c3c --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/DhAddCar.java @@ -0,0 +1,48 @@ +package me.zhengjie.entity; + +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 敦煌加入购物车(DhAddCar)表实体类 + * + * @author rch + * @since 2022-11-17 09:11:54 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DhAddCar extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 买家ID */ + private Long buyerId; + /** 商品属性类型:1.关键词 2.链接 */ + private Integer paramsType; + /** 加购物车商品ids */ + private String carGoodIds; + /** 执行结果 */ + private String response; + /** 状态 1.待执行 2.执行中 3.加购成功 4.加购失败 5.下单成功 6.支付成功 7.抓单成功 8.抓单失败 */ + private Integer status; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/DhAddCarOrder.java b/wjcy-common/src/main/java/me/zhengjie/entity/DhAddCarOrder.java new file mode 100644 index 0000000..6c656d4 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/DhAddCarOrder.java @@ -0,0 +1,55 @@ +package me.zhengjie.entity; + +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 敦煌-加购物车-订单(DhAddCarOrder)表实体类 + * + * @author rch + * @since 2022-11-17 09:11:58 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DhAddCarOrder extends Model { + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 1.导入 2.刷单 */ + private Integer type; + /** 关联敦煌加购的id */ + private Long addCarId; +// /** 关联敦煌加购的ids */ +// private Long addCarIds; + /** 总金额 */ + private String amount; + /** 状态描述 */ + private String paymentResults; + /** 店铺名称 */ + private String shop; + /** 订单id */ + private String orderId; + /** 时间 */ + private String orderDate; + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 */ + private Integer status; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/DhCarGoods.java b/wjcy-common/src/main/java/me/zhengjie/entity/DhCarGoods.java new file mode 100644 index 0000000..e19bc32 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/DhCarGoods.java @@ -0,0 +1,62 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * 敦煌-加入购物车商品信息(DhCarGoods)表实体类 + * + * @author makejava + * @since 2022-11-17 09:12:02 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DhCarGoods extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + /** 商品属性类型:1.关键词 2.链接 */ + private Integer paramsType; + /** 店铺名称 */ + private String shopName; + /** 关键词 */ + private String keyWord; + /** 标题 */ + private String title; + /** 链接 */ + private String link; + /** 数量 */ + private Integer number; + /** 规格 */ + private String specification; + /** 颜色 */ + private String color; + /** item */ + private String item; + /** 最小价格区间 */ + private String sectionMin; + /** 最大价格区间 */ + private String sectionMax; + /** 评论 */ + private String comment; + /** 图片url */ + private String paths; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/ExcelImportInfo.java b/wjcy-common/src/main/java/me/zhengjie/entity/ExcelImportInfo.java new file mode 100644 index 0000000..4090e67 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/ExcelImportInfo.java @@ -0,0 +1,38 @@ +//package me.zhengjie.entity; +// +//import lombok.AllArgsConstructor; +//import lombok.Data; +//import lombok.NoArgsConstructor; +//import me.zhengjie.utils.excel.ExcelImport; +// +///** +// * Excel导入信息实体类 +// * +// * @author rch +// * @create 2022-06-23 +// */ +//@Data +//@AllArgsConstructor +//@NoArgsConstructor +//public class ExcelImportInfo { +// /** 公司主键 */ +// @ExcelImport("公司主键") +// private Long companyId; +// +// /** 鉴权枚举 */ +// @ExcelImport("鉴权枚举") +// private Integer tokenEnum; +// +// /** 订单来源 */ +// @ExcelImport("订单来源") +// private String fromDetailInfo; +// +// /** 产品信息-JSON */ +// @ExcelImport("产品信息") +// private String cartList; +// +// /** 订单收货地址-JSON */ +// @ExcelImport("订单收货地址") +// private String contactInfo; +// +//} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/LoginIp.java b/wjcy-common/src/main/java/me/zhengjie/entity/LoginIp.java new file mode 100644 index 0000000..8a20668 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/LoginIp.java @@ -0,0 +1,39 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +/** + * (LoginIp)表实体类 + * + * @author rch + * @since 2022-06-23 + */ +@Data +public class LoginIp extends Model { + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + @TableField(fill = FieldFill.INSERT) + private String createdAt; + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedAt; + + /** 开始IP */ + private String ipStart; + /** 结束IP */ + private String ipEnd; + /** 备注 */ + private String remark; + /** 有效截至时间 */ + private String vaildTime; + /** 操作账号 */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/QueryWrapperAndPage.java b/wjcy-common/src/main/java/me/zhengjie/entity/QueryWrapperAndPage.java new file mode 100644 index 0000000..48d8f52 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/QueryWrapperAndPage.java @@ -0,0 +1,15 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class QueryWrapperAndPage { + QueryWrapper queryWrapper; + Page page; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/ResultObj.java b/wjcy-common/src/main/java/me/zhengjie/entity/ResultObj.java new file mode 100644 index 0000000..21e6c83 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/ResultObj.java @@ -0,0 +1,20 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 影刀回调响应-resultObj + * + * @author rch + * @create 2022-08-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ResultObj { + private String name; + private String type; + private String value; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/ReturnObje.java b/wjcy-common/src/main/java/me/zhengjie/entity/ReturnObje.java new file mode 100644 index 0000000..46d863c --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/ReturnObje.java @@ -0,0 +1,28 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 影刀回调返回值-ReturnObj + * + * @author rch + * @create 2022-08-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ReturnObje { + private String msg; + private List result; + private String jobUuid; + private String robotClientName; + private String robotName; + private String robotClientUuid; + private String startTime; + private String endTime; + private String status; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/SysQuartzJob.java b/wjcy-common/src/main/java/me/zhengjie/entity/SysQuartzJob.java new file mode 100644 index 0000000..cdab873 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/SysQuartzJob.java @@ -0,0 +1,70 @@ +package me.zhengjie.entity; + +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * 定时任务(SysQuartzJob)表实体类 + * + * @author rch + * @since 2022-07-20 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SysQuartzJob extends Model { + + public static final String JOB_KEY = "JOB_KEY"; + + @TableId(value = "job_id", type = IdType.AUTO) + private Long jobId; + + private String createTime; + private String updateTime; + /** 操作人账号*/ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String gmName; + + private Long taskNum; + /** 类型 1.普通 2.影刀 */ + private Integer type; + /** Spring Bean名称 */ + private String beanName; + /** cron 表达式 */ + private String cronExpression; + /** 状态:1暂停、0启用 */ + private Integer isPause; + /** 任务名称 */ + private String jobName; + /** 方法名称 */ + private String methodName; + /** 参数 */ + private String params; + /** 参数类型 */ + private Integer paramsType; + /** 备注 */ + private String description; + /** 负责人 */ + private String personInCharge; + /** 报警邮箱 */ + private String email; + /** 子任务ID */ + private String subTask; + /** 任务失败后是否暂停 */ + private Integer pauseAfterFailure; + /** 创建者 */ + private String createBy; + /** 更新者 */ + private String updateBy; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/SysQuartzLog.java b/wjcy-common/src/main/java/me/zhengjie/entity/SysQuartzLog.java new file mode 100644 index 0000000..3ed54bf --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/SysQuartzLog.java @@ -0,0 +1,58 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.sql.Timestamp; + +/** + * @author rch + * @date 2022-07-20 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SysQuartzLog extends Model { + + private Long logId; + /** bean名称 */ + private String beanName; + /** 方法名称 */ + private String methodName; + + /** 参数 */ + private String params; + + /** cron表达式 */ + private String cronExpression; + + /** 状态 */ + private Boolean isSuccess; + + /** 异常详情 */ + private String exceptionDetail; + + /** 执行耗时 */ + private Long time; + + /** 创建时间 */ + private Timestamp createTime; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/YdSign.java b/wjcy-common/src/main/java/me/zhengjie/entity/YdSign.java new file mode 100644 index 0000000..7e69897 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/YdSign.java @@ -0,0 +1,32 @@ +package me.zhengjie.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 影刀 鉴权 + * + * @author rch + * @since 2022-07-26 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class YdSign extends Model { + + /** 时间戳 */ + private Long timestamp; + /** accessKeyId */ + private String accessKeyId; + /** accessKeySecret */ + private String accessKeySecret; + /** bodyMd5 */ + private String bodyMd5; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/YdStartReturn.java b/wjcy-common/src/main/java/me/zhengjie/entity/YdStartReturn.java new file mode 100644 index 0000000..abf9b72 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/YdStartReturn.java @@ -0,0 +1,24 @@ +package me.zhengjie.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 调用影刀启动任务响应信息 + * + * @author rch + * @create 2022-08-24 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class YdStartReturn { + private String code; + private Boolean success; + private TaskUuid data; +} + +class TaskUuid { + private String taskUuid; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/quartz/Boss.java b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/Boss.java new file mode 100644 index 0000000..b6cd0db --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/Boss.java @@ -0,0 +1,23 @@ +package me.zhengjie.entity.quartz; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 调用影刀json信息 + * + * @author rch + * @create 2022-08-01 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Boss { + private String accountName; + private String robotUuid; + private Long applyId; + private List params; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/quartz/DataInfo.java b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/DataInfo.java new file mode 100644 index 0000000..97d9a32 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/DataInfo.java @@ -0,0 +1,19 @@ +package me.zhengjie.entity.quartz; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 调用影刀响应子集信息 + * + * @author rch + * @create 2022-08-01 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DataInfo { + private String accessToken; + private String expiresIn; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryByUuid.java b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryByUuid.java new file mode 100644 index 0000000..f80e95d --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryByUuid.java @@ -0,0 +1,18 @@ +package me.zhengjie.entity.quartz; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 根据影刀任务ID查询影刀任务执行信息 + * + * @author rch + * @create 2022-08-01 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class JobQueryByUuid { + private String jobUuid; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryByUuidData.java b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryByUuidData.java new file mode 100644 index 0000000..54bc9f6 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryByUuidData.java @@ -0,0 +1,28 @@ +package me.zhengjie.entity.quartz; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 根据影刀任务id 查询影刀任务详情信息 + * + * @author rch + * @create 2022-08-01 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class JobQueryByUuidData { + private JobQueryByUuidRobotParams robotParams; + private String jobUuid; + private String status; + private String statusName; + private String robotUuid; + private String robotName; + private String startTime; + private String endTime; + private String remark; + private String robotClientUuid; + private String robotClientName; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryByUuidReturn.java b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryByUuidReturn.java new file mode 100644 index 0000000..3217b49 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryByUuidReturn.java @@ -0,0 +1,93 @@ +package me.zhengjie.entity.quartz; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 根据影刀任务id 查询影刀任务详情信息 + * + * @author rch + * @create 2022-08-01 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class JobQueryByUuidReturn { + private String code; + private Boolean success; + private JobQueryByUuidData data; + + /** + * { + * "data": { + * "jobUuid": "e925cd35-6857-48ae-a4ef-40ceea975e50", + * "status": "error", + * "statusName": "异常", + * "robotUuid": "9107fa36-a6d0-4ac6-932f-8fcbb7deb89b", + * "robotName": "刷单系统", + * "startTime": "2022-09-09 15:14:32", + * "endTime": "2022-09-09 15:15:52", + * "remark": "【e925cd35-6857-48ae-a4ef-40ceea975e50】任务失败,在【1-2清空浏览器数据】中第1行:出错:The tab was closed.", + * "robotParams": { + * "inputs": [ + * { + * "name": "id", + * "value": "4", + * "type": "str" + * }, + * { + * "name": "country", + * "value": "Korea", + * "type": "str" + * }, + * { + * "name": "account", + * "value": "borislanphere553@gmail.com", + * "type": "str" + * }, + * { + * "name": "pwd", + * "value": "sdwjcy2021", + * "type": "str" + * }, + * { + * "name": "keyWord", + * "value": "neck electric massage", + * "type": "str" + * }, + * { + * "name": "number", + * "value": "10", + * "type": "str" + * }, + * { + * "name": "specification", + * "value": "type-c", + * "type": "str" + * }, + * { + * "name": "color", + * "value": "Full Function", + * "type": "str" + * }, + * { + * "name": "item", + * "value": "1005001346919788", + * "type": "str" + * }, + * { + * "name": "vpnShare", + * "value": "ew0KICAidiI6ICIyIiwNCiAgInBzIjogIjEwNC4yMjEuMTk5LjgyIiwNCiAgImFkZCI6ICJ1cy1lczM0LmZvYmhlbHAuY29tIiwNCiAgInBvcnQiOiAiMzAwNDMiLA0KICAiaWQiOiAiYzA4NDk5ODQtZWNjNC01MzY3LTlmOTctYTI2ODljNTQ5N2QyIiwNCiAgImFpZCI6ICI2NCIsDQogICJzY3kiOiAiYXV0byIsDQogICJuZXQiOiAidGNwIiwNCiAgInR5cGUiOiAibm9uZSIsDQogICJob3N0IjogIiIsDQogICJwYXRoIjogIiIsDQogICJ0bHMiOiAiIiwNCiAgInNuaSI6ICIiDQp9", + * "type": "str" + * } + * ] + * }, + * "robotClientUuid": "13d29cc7-3feb-46b5-a02c-66dced9dfeca", + * "robotClientName": "linbiaoyuan@vogocm" + * }, + * "code": 200, + * "success": true + * } + */ +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryByUuidRobotParams.java b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryByUuidRobotParams.java new file mode 100644 index 0000000..64c3501 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryByUuidRobotParams.java @@ -0,0 +1,22 @@ +package me.zhengjie.entity.quartz; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.entity.ResultObj; + +import java.util.List; + +/** + * 根据影刀任务id查询影刀 + * + * @author rch + * @create 2022-09-09 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class JobQueryByUuidRobotParams { + private List inputs; + private List outputs; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryReturnResult.java b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryReturnResult.java new file mode 100644 index 0000000..5958ca9 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/JobQueryReturnResult.java @@ -0,0 +1,22 @@ +package me.zhengjie.entity.quartz; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 根据影刀任务id 查询影刀任务详情信息 + * + * @author rch + * @create 2022-08-01 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class JobQueryReturnResult { + private String id; + private String status; + private String statusName; + private String code; + private Boolean success; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/quartz/Param.java b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/Param.java new file mode 100644 index 0000000..921efcd --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/Param.java @@ -0,0 +1,20 @@ +package me.zhengjie.entity.quartz; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 调用影刀真正入参信息 + * + * @author rch + * @create 2022-08-01 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Param { + private String name; + private String value; + private String type = "str"; +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/quartz/Params.java b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/Params.java new file mode 100644 index 0000000..a5782be --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/Params.java @@ -0,0 +1,22 @@ +package me.zhengjie.entity.quartz; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 调用影刀json信息 params里的 params是一个跟业务相关的主建 + * + * @author rch + * @create 2022-08-01 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Params { + private String accountName; + private Long applyId; + private String params; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/quartz/RebotStatu.java b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/RebotStatu.java new file mode 100644 index 0000000..415baad --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/RebotStatu.java @@ -0,0 +1,19 @@ +package me.zhengjie.entity.quartz; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 机器人相应信息子集 + * + * @author rch + * @create 2022-08-01 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RebotStatu { + private String robotClientUuid; + private String accountName; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/quartz/RebotStatuInfo.java b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/RebotStatuInfo.java new file mode 100644 index 0000000..33f5e40 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/RebotStatuInfo.java @@ -0,0 +1,29 @@ +package me.zhengjie.entity.quartz; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 影刀机器人状态信息 + * + * @author rch + * @create 2022-08-01 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RebotStatuInfo { + /** 状态 connected:已连接 idle:空闲 running:运行中 allocated:已分配 abnormal:异常 offline:离线 */ + private String status; + /** 机器人客户端ip */ + private String clientIp; + /** 机器人uuid */ + private String robotClientUuid; + /** 机器人名称 */ + private String robotClientName; + /** 机器人备注 */ + private String description; + /** 运行备注 */ + private String remark; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/quartz/RebotStatuReturn.java b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/RebotStatuReturn.java new file mode 100644 index 0000000..20b7669 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/RebotStatuReturn.java @@ -0,0 +1,20 @@ +package me.zhengjie.entity.quartz; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 机器人相应信息 + * + * @author rch + * @create 2022-08-01 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RebotStatuReturn { + private String code; + private Boolean success; + private RebotStatuInfo data; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/quartz/SecreInfo.java b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/SecreInfo.java new file mode 100644 index 0000000..c835970 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/SecreInfo.java @@ -0,0 +1,21 @@ +package me.zhengjie.entity.quartz; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 调用影刀相应信息 + * + * @author rch + * @create 2022-08-01 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SecreInfo { + private String code; + private Boolean success; + private String requestId; + private DataInfo data; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/entity/quartz/StartYdReturnInfo.java b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/StartYdReturnInfo.java new file mode 100644 index 0000000..fffefe0 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/entity/quartz/StartYdReturnInfo.java @@ -0,0 +1,22 @@ +package me.zhengjie.entity.quartz; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 启动影刀任务响应信息 + * + * @author rch + * @create 2022-10-27 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class StartYdReturnInfo { + private String code; + private Boolean success; + private String requestId; + private String serverInstName; + private String msg; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/BuyerLevelEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/BuyerLevelEnum.java new file mode 100644 index 0000000..cb93bf3 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/BuyerLevelEnum.java @@ -0,0 +1,77 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 用户等级 1.普通 2.精品 3.压力 4.内部账号 + *

+ * + * @Author rch + * @Date 2022-07-18 + **/ +public enum BuyerLevelEnum implements IntegerEnum { + /** + * 用户等级 1.普通 2.精品 3.压力 4.内部账号 + */ + + GENERAL(1), + BOUTIQUR(2), + PRESSURE(3), + INNER_ACCOUNT(4); + + private final Integer value; + + private BuyerLevelEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static BuyerLevelEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (BuyerLevelEnum obj : EnumUtils.getEnumList(BuyerLevelEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/BuyerOccupyStatusEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/BuyerOccupyStatusEnum.java new file mode 100644 index 0000000..3c09adb --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/BuyerOccupyStatusEnum.java @@ -0,0 +1,75 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 占用状态 1.已占用 2.未占用 + *

+ * + * @Author rch + * @Date 2022-07-18 + **/ +public enum BuyerOccupyStatusEnum implements IntegerEnum { + /** + * 占用状态 1.已占用 2.未占用 + */ + + OCCUPIED(1), + UN_OCCUPIED(2); + + private final Integer value; + + private BuyerOccupyStatusEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static BuyerOccupyStatusEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (BuyerOccupyStatusEnum obj : EnumUtils.getEnumList(BuyerOccupyStatusEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/BuyerStatusEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/BuyerStatusEnum.java new file mode 100644 index 0000000..eb64052 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/BuyerStatusEnum.java @@ -0,0 +1,80 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 状态(导入默认正常) 1.待注册 2待验证 3.待完善 4.正常 5.异常 6.可用但已用 7.删除 + *

+ * + * @Author rch + * @Date 2022-06-23 + **/ +public enum BuyerStatusEnum implements IntegerEnum { + /** + * 状态(导入默认正常) 1.待注册 2待验证 3.待完善 4.正常 5.异常 6.可用但已用 7.删除', + */ + + TOBE_REGISTER(1), + TOBE_CHECKING(2), + TOBE_PERFECT(3), + NORMAL(4), + AB_NORMAL(5), + AVAILABLE_BUT_USED(6), + DEL(7); + + private final Integer value; + + private BuyerStatusEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static BuyerStatusEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (BuyerStatusEnum obj : EnumUtils.getEnumList(BuyerStatusEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/CardDealerTypeEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/CardDealerTypeEnum.java new file mode 100644 index 0000000..de8c646 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/CardDealerTypeEnum.java @@ -0,0 +1,75 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 信用卡所属厂商类型 枚举 + *

+ * + * @Author rch + * @Date 2022-07-09 + **/ +public enum CardDealerTypeEnum implements IntegerEnum { + /** + * 所属厂商:1.AmzKeys 2.Airwallex + */ + + AMZKEYS(1), + AIRWALLEX(2); + + private final Integer value; + + private CardDealerTypeEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static CardDealerTypeEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (CardDealerTypeEnum obj : EnumUtils.getEnumList(CardDealerTypeEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/CardStatusEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/CardStatusEnum.java new file mode 100644 index 0000000..7c2966e --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/CardStatusEnum.java @@ -0,0 +1,76 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 信用卡类状态枚举 + *

+ * + * @Author rch + * @Date 2022-07-11 + **/ +public enum CardStatusEnum implements IntegerEnum { + /** + * 状态:1.正常、2.异常、3.已删除 + */ + + NORMAL(1), + AB_NORMAL(2), + DEL(3); + + private final Integer value; + + private CardStatusEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static CardStatusEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (CardStatusEnum obj : EnumUtils.getEnumList(CardStatusEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/CardTypeEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/CardTypeEnum.java new file mode 100644 index 0000000..24db1b5 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/CardTypeEnum.java @@ -0,0 +1,76 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 信用卡类型 枚举 + *

+ * + * @Author rch + * @Date 2022-07-09 + **/ +public enum CardTypeEnum implements IntegerEnum { + /** + * 信用卡类型 1.Payoneer 2.万事达虚拟卡 3.Visa信用卡 + */ + + PAYONEER(1), + WSD_INVENTED(2), + VISA(3); + + private final Integer value; + + private CardTypeEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static CardTypeEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (CardTypeEnum obj : EnumUtils.getEnumList(CardTypeEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/ClickBrowseStatusEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/ClickBrowseStatusEnum.java new file mode 100644 index 0000000..650fd7d --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/ClickBrowseStatusEnum.java @@ -0,0 +1,77 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 浏览好评状态枚举 + *

+ * + * @Author rch + * @Date 2022-11-07 + **/ +public enum ClickBrowseStatusEnum implements IntegerEnum { + /** + * 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 + */ + + TOBE_EXECUTION(1), + IN_EXECUTION(2), + EXECUTION_SUCCESS(3), + EXECUTION_FAILE(4); + + private final Integer value; + + private ClickBrowseStatusEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static ClickBrowseStatusEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (ClickBrowseStatusEnum obj : EnumUtils.getEnumList(ClickBrowseStatusEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/ClickFarmingStatusEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/ClickFarmingStatusEnum.java new file mode 100644 index 0000000..2f0ae99 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/ClickFarmingStatusEnum.java @@ -0,0 +1,79 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 刷单状态枚举 + *

+ * + * @Author rch + * @Date 2022-07-11 + **/ +public enum ClickFarmingStatusEnum implements IntegerEnum { + /** + * 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 5.待支付 6.支付成功异常 (加购比较特殊 判断是否有订单号, 执行成功没有订单号是加购物车成功,区分抓单成功) + */ + + TOBE_EXECUTION(1), + IN_EXECUTION(2), + EXECUTION_SUCCESS(3), + EXECUTION_FAILE(4), + AWAITING_PAYMENT(5), + PAY_OK_ERROR(6); + + private final Integer value; + + private ClickFarmingStatusEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static ClickFarmingStatusEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (ClickFarmingStatusEnum obj : EnumUtils.getEnumList(ClickFarmingStatusEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/ClickOrderStatusEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/ClickOrderStatusEnum.java new file mode 100644 index 0000000..5530634 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/ClickOrderStatusEnum.java @@ -0,0 +1,77 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 刷单订单状态枚举 + *

+ * + * @Author rch + * @Date 2022-07-11 + **/ +public enum ClickOrderStatusEnum implements IntegerEnum { + /** + * 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 + */ + + TOBE_EXECUTION(1), + IN_EXECUTION(2), + EXECUTION_SUCCESS(3), + EXECUTION_FAILE(4); + + private final Integer value; + + private ClickOrderStatusEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static ClickOrderStatusEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (ClickOrderStatusEnum obj : EnumUtils.getEnumList(ClickOrderStatusEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/CtReboteStatusEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/CtReboteStatusEnum.java new file mode 100644 index 0000000..a4e828b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/CtReboteStatusEnum.java @@ -0,0 +1,75 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 机器人 状态0.未占用 1.占用 + *

+ * + * @Author xxs + * @Date 2021/9/26 + **/ +public enum CtReboteStatusEnum implements IntegerEnum { + /** + * 状态0.未占用 1.占用 + */ + + UNOCCUPIED(0), + OCCUPY(1); + + private final Integer value; + + private CtReboteStatusEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static CtReboteStatusEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (CtReboteStatusEnum obj : EnumUtils.getEnumList(CtReboteStatusEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/DhAddCarStatusEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/DhAddCarStatusEnum.java new file mode 100644 index 0000000..9c7ed42 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/DhAddCarStatusEnum.java @@ -0,0 +1,82 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 敦煌加购状态枚举 + *

+ * + * @Author rch + * @Date 2022-07-11 + **/ +public enum DhAddCarStatusEnum implements IntegerEnum { + /** + * 状态 1.待执行 2.执行中 3.加购成功 4.加购失败 5.下单成功 6.待抓单 7.抓单中 8.抓单成功 9.抓单失败 + */ + + TOBE_EXECUTION(1), + IN_EXECUTION(2), + Add_CARD_SUCCESS(3), + ADD_CARD_FAILE(4), + ORDER_SUCCESS(5), + TO_BE_CATCH_ORDER(6), + CATCH_ORDER_ING(7), + CATCH_ORDER_SUCCESS(8), + CATCH_ORDER_FAILE(9); + + private final Integer value; + + private DhAddCarStatusEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static DhAddCarStatusEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (DhAddCarStatusEnum obj : EnumUtils.getEnumList(DhAddCarStatusEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/DhPayStatusEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/DhPayStatusEnum.java new file mode 100644 index 0000000..a232181 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/DhPayStatusEnum.java @@ -0,0 +1,77 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 敦煌支付状态枚举 + *

+ * + * @Author rch + * @Date 2022-07-28 + **/ +public enum DhPayStatusEnum implements IntegerEnum { + /** + * 状态 0.待处理 1.支付成功 2.支付失败 + */ + + TO_BE(0), + PAY_SUCCESS(1), + PAY_FAIL(2), + DEL(3); + + private final Integer value; + + private DhPayStatusEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static DhPayStatusEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (DhPayStatusEnum obj : EnumUtils.getEnumList(DhPayStatusEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/ExcelInfoRequestTypeEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/ExcelInfoRequestTypeEnum.java new file mode 100644 index 0000000..65a14d2 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/ExcelInfoRequestTypeEnum.java @@ -0,0 +1,75 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 请求类型:1.下单请求 2.支付请求 + *

+ * + * @Author rch + * @Date 2022-06-23 + **/ +public enum ExcelInfoRequestTypeEnum implements IntegerEnum { + /** + * 请求类型:1.下单请求 2.支付请求 + */ + + BUY_ORDER(1), + PAY_ORDER(2); + + private final Integer value; + + private ExcelInfoRequestTypeEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static ExcelInfoRequestTypeEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (ExcelInfoRequestTypeEnum obj : EnumUtils.getEnumList(ExcelInfoRequestTypeEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/ExcelStatusEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/ExcelStatusEnum.java new file mode 100644 index 0000000..9cdce5e --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/ExcelStatusEnum.java @@ -0,0 +1,76 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 状态1.待导入 2.导入成功 3.导入失败 + *

+ * + * @Author rch + * @Date 2022-06-23 + **/ +public enum ExcelStatusEnum implements IntegerEnum { + /** + * 状态1.待导入 2.导入成功 3.导入失败 + */ + + TOBE(1), + SUCCESS(2), + FAILE(3); + + private final Integer value; + + private ExcelStatusEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static ExcelStatusEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (ExcelStatusEnum obj : EnumUtils.getEnumList(ExcelStatusEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/LanguageEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/LanguageEnum.java new file mode 100644 index 0000000..79ce4d8 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/LanguageEnum.java @@ -0,0 +1,38 @@ +package me.zhengjie.enums; + +/** + * 多语言枚举类 + * + * @author zeng + * @since 2021/08/24 10:08 + */ + +public enum LanguageEnum { + + ZH("简体中文"), + + EN("英文"), + + CW("繁体中文"), + ; + + private final String des; + + LanguageEnum(String des) { + this.des = des; + } + + public String getValue() { + return this.name().toLowerCase(); + } + + public static boolean isInclude(String language) { + for (LanguageEnum value : LanguageEnum.values()) { + if (value.getValue().equals(language)) { + return true; + } + } + return false; + } + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/OrderTypeEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/OrderTypeEnum.java new file mode 100644 index 0000000..238cda8 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/OrderTypeEnum.java @@ -0,0 +1,75 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 刷单订单类型枚举 + *

+ * + * @Author rch + * @Date 2022-10-24 + **/ +public enum OrderTypeEnum implements IntegerEnum { + /** + * 状态 1.导入 2.刷单 + */ + + IMPORT(1), + CLICK_FARMING(2); + + private final Integer value; + + private OrderTypeEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static OrderTypeEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (OrderTypeEnum obj : EnumUtils.getEnumList(OrderTypeEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/ParamsTypeEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/ParamsTypeEnum.java new file mode 100644 index 0000000..59a9f18 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/ParamsTypeEnum.java @@ -0,0 +1,75 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 参数类型类型 枚举 + *

+ * + * @Author rch + * @Date 2022-07-09 + **/ +public enum ParamsTypeEnum implements IntegerEnum { + /** + * 商品属性类型:1.关键词 2.链接 + */ + + KEY_WORD(1), + LINK(2); + + private final Integer value; + + private ParamsTypeEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static ParamsTypeEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (ParamsTypeEnum obj : EnumUtils.getEnumList(ParamsTypeEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/PlatTypeEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/PlatTypeEnum.java new file mode 100644 index 0000000..3b96ba6 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/PlatTypeEnum.java @@ -0,0 +1,92 @@ +package me.zhengjie.enums; + +import org.apache.commons.lang3.EnumUtils; + +import java.util.Arrays; + +/** + *

+ * 平台类型 1.敦煌 + *

+ * + * @Author rch + * @Date 2022-07-06 + **/ +public enum PlatTypeEnum { + + //平台类型 1.敦煌 + DH(1, "敦煌"), + SMT(2, "速卖通"), + MB(3, "马帮"); + + + private final Integer type; + private final String desc; + + private PlatTypeEnum(Integer type, String desc) { + this.type = type; + this.desc = desc; + } + + public static String getDescByType(Integer type) { + if (type == null) { + return ""; + } + PlatTypeEnum[] enumAry = PlatTypeEnum.values(); + for(int i = 0; i < Arrays.asList(enumAry).size(); i++){ + if (enumAry[i].getType().equals(type)) { + return enumAry[i].getDesc(); + } + } + return ""; + } + + public static Integer getValueByDesc(String desc) { + PlatTypeEnum[] enumAry = PlatTypeEnum.values(); + for (PlatTypeEnum currencyTypeEnum : enumAry) { + if (currencyTypeEnum.getDesc().equals(desc)) { + return currencyTypeEnum.getType(); + } + } + return null; + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static PlatTypeEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (PlatTypeEnum obj : EnumUtils.getEnumList(PlatTypeEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } + + /** + * 值相等 + * + * @param value + * @return + */ + public boolean eqValue(Integer value) { + if (value != null && type.equals(value)) { + return true; + } + return false; + } + + public Integer getType() { + return type; + } + + public String getDesc() { + return desc; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/RobotStatusEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/RobotStatusEnum.java new file mode 100644 index 0000000..adcaa1c --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/RobotStatusEnum.java @@ -0,0 +1,77 @@ +package me.zhengjie.enums; + +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 机器人状态 枚举 + *

+ * + * @Author rch + * @Date 2022-07-09 + **/ +public enum RobotStatusEnum{ + /** + * 状态 connected:已连接 idle:空闲 running:运行中 allocated:已分配 abnormal:异常 offline:离线 + */ + + CONNECTED("connected"), + IDLE("idle"), + RUNNING("running"), + ALLOCATED("allocated"), + ABNORMAL("abnormal"), + OFFLINE("offline"); + + private final String value; + + private RobotStatusEnum(String value) { + this.value = value; + } + + + public String value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(String value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(String value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static RobotStatusEnum getEnum(String value) { + if (value == null) { + return null; + } + for (RobotStatusEnum obj : EnumUtils.getEnumList(RobotStatusEnum.class)) { + if (obj.value().equals(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/TaskInfoEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/TaskInfoEnum.java new file mode 100644 index 0000000..421bff1 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/TaskInfoEnum.java @@ -0,0 +1,54 @@ +package me.zhengjie.enums; + +import java.util.Arrays; + +/** + *

+ * Task 信息枚举 包含task基本信息 + *

+ * + * @Author rch + * @Date 2022-08-01 + **/ +public enum TaskInfoEnum { + + // 1.Demo-Task + BOSS_TASK("bossTask", "run"), + CLICK_FARMING("clickFarmTask", "run"), + CLICK_FARMING_SUPPLE_MENY("clickFarmSuppleMentTask", "run"), + WELL_RECEIVED("wellReceivedTask", "run"), + BROWSE("browseTask", "run"), + DH_ADD_CAR_FARMING("dhAddCarTask", "run"), + DH_ADD_CAR_CATCH_ORDER("dhCatchOrderTask", "run"), + DH_WELL_RECEIVED("dhWellReceivedTask", "run"); + + + private final String taskName; + private final String methodName; + + private TaskInfoEnum(String taskName, String methodName) { + this.taskName = taskName; + this.methodName = methodName; + } + + public static String getMethodNameByTaskName(String taskName) { + if (taskName == null) { + return ""; + } + TaskInfoEnum[] enumAry = TaskInfoEnum.values(); + for(int i = 0; i < Arrays.asList(enumAry).size(); i++){ + if (enumAry[i].getTaskName().equals(taskName)) { + return enumAry[i].getMethodName(); + } + } + return ""; + } + + public String getTaskName() { + return taskName; + } + + public String getMethodName() { + return methodName; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/TaskIsPauseEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/TaskIsPauseEnum.java new file mode 100644 index 0000000..440f9f0 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/TaskIsPauseEnum.java @@ -0,0 +1,75 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 状态 1.暂停 2.启用 + *

+ * + * @Author rch + * @Date 2022-10-06 + **/ +public enum TaskIsPauseEnum implements IntegerEnum { + /** + * 类型 1.暂停 0.启用 + */ + + IS_PAUSE(1), + NOT_PAUSE(0); + + private final Integer value; + + private TaskIsPauseEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static TaskIsPauseEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (TaskIsPauseEnum obj : EnumUtils.getEnumList(TaskIsPauseEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/TaskTypeEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/TaskTypeEnum.java new file mode 100644 index 0000000..6f25196 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/TaskTypeEnum.java @@ -0,0 +1,75 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * 类型 1.普通 2.影刀 + *

+ * + * @Author rch + * @Date 2022-07-20 + **/ +public enum TaskTypeEnum implements IntegerEnum { + /** + * 类型 1.普通 2.影刀 + */ + + ORDINARY(1), + SHADOW_KNIFE(2); + + private final Integer value; + + private TaskTypeEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static TaskTypeEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (TaskTypeEnum obj : EnumUtils.getEnumList(TaskTypeEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/VpnDealerEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/VpnDealerEnum.java new file mode 100644 index 0000000..b08953e --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/VpnDealerEnum.java @@ -0,0 +1,74 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * VPN经销商枚举 + *

+ * + * @Author zhw + * @Date 2022-07-18 + **/ +public enum VpnDealerEnum implements IntegerEnum { + /** + * 状态:1.V2 + */ + + V2(1); + + private final Integer value; + + private VpnDealerEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static VpnDealerEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (VpnDealerEnum obj : EnumUtils.getEnumList(VpnDealerEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/VpnStatusEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/VpnStatusEnum.java new file mode 100644 index 0000000..b246388 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/VpnStatusEnum.java @@ -0,0 +1,75 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * VPN类状态枚举 + *

+ * + * @Author zhw + * @Date 2022-07-18 + **/ +public enum VpnStatusEnum implements IntegerEnum { + /** + * 状态:1.可用、2.禁用 + */ + + AVAILABLE(1), + DISABLED(2); + + private final Integer value; + + private VpnStatusEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static VpnStatusEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (VpnStatusEnum obj : EnumUtils.getEnumList(VpnStatusEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/VpnTypeEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/VpnTypeEnum.java new file mode 100644 index 0000000..b52d540 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/VpnTypeEnum.java @@ -0,0 +1,74 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * VPN类型枚举 + *

+ * + * @Author zhw + * @Date 2022-07-18 + **/ +public enum VpnTypeEnum implements IntegerEnum { + /** + * 状态:1.传统 + */ + + TRADITION(1); + + private final Integer value; + + private VpnTypeEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static VpnTypeEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (VpnTypeEnum obj : EnumUtils.getEnumList(VpnTypeEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/YesOrNoEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/YesOrNoEnum.java new file mode 100644 index 0000000..5b58315 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/YesOrNoEnum.java @@ -0,0 +1,75 @@ +package me.zhengjie.enums; + +import me.zhengjie.enums.interfaces.IntegerEnum; +import org.apache.commons.lang3.EnumUtils; + +/** + *

+ * Yes or No + *

+ * + * @Author xxs + * @Date 2021/9/26 + **/ +public enum YesOrNoEnum implements IntegerEnum { + /** + * 类型型(1.YES 0.NO ) + */ + + YES(1), + NO(0); + + private final Integer value; + + private YesOrNoEnum(Integer value) { + this.value = value; + } + + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static YesOrNoEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (YesOrNoEnum obj : EnumUtils.getEnumList(YesOrNoEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/interfaces/IntegerEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/interfaces/IntegerEnum.java new file mode 100644 index 0000000..f944411 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/interfaces/IntegerEnum.java @@ -0,0 +1,40 @@ +package me.zhengjie.enums.interfaces; + +/** + *

+ * Integer类型枚举 + *

+ * + * @Author xx + * @Date 2021/7/22 + **/ +public interface IntegerEnum { + + /**值 + * @return + */ + Integer value(); + + /** + * 值相等 + * + * @param value + * @return + */ + default boolean eqValue(Integer value) { + if (value != null && value().equals(value)) { + return true; + } + return false; + } + + /** + * 值不相等 + * + * @param value + * @return + */ + default boolean neValue(Integer value) { + return !eqValue(value); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/interfaces/LongEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/interfaces/LongEnum.java new file mode 100644 index 0000000..8b210fa --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/interfaces/LongEnum.java @@ -0,0 +1,40 @@ +package me.zhengjie.enums.interfaces; + +/** + *

+ * Long类型枚举 + *

+ * + * @Author xx + * @Date 2021/7/22 + **/ +public interface LongEnum { + + /**值 + * @return + */ + Long value(); + + /** + * 值相等 + * + * @param value + * @return + */ + default boolean eqValue(Long value) { + if (value != null && value().equals(value)) { + return true; + } + return false; + } + + /** + * 值不相等 + * + * @param value + * @return + */ + default boolean neValue(Long value) { + return !eqValue(value); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/enums/interfaces/MemberIsUsedEnum.java b/wjcy-common/src/main/java/me/zhengjie/enums/interfaces/MemberIsUsedEnum.java new file mode 100644 index 0000000..e5992be --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/enums/interfaces/MemberIsUsedEnum.java @@ -0,0 +1,71 @@ +package me.zhengjie.enums.interfaces; + +import org.apache.commons.lang3.EnumUtils; +/** + *

+ * 用户是否使用过 + *

+ * + * @Author xx + * @Date 2021/8/11 + **/ +public enum MemberIsUsedEnum implements IntegerEnum { + /** 未使用 */ + UN_USED(0), + /** 已使用*/ + IS_USED(1); + + private final Integer value; + + private MemberIsUsedEnum(Integer value) { + this.value = value; + } + + @Override + public Integer value() { + return this.value; + } + + /** + * 判断是否存在指定值 + * + * @param value + * @return + */ + public static boolean hasValue(Integer value) { + boolean hasVal = false; + if (getEnum(value) != null) { + hasVal = true; + } + return hasVal; + } + + /** + * 判断是否不存在指定值 + * + * @param value + * @return + */ + public static boolean notHasValue(Integer value) { + return !hasValue(value); + } + + /** + * 获取指定值对应的枚举 + * + * @param value + * @return + */ + public static MemberIsUsedEnum getEnum(Integer value) { + if (value == null) { + return null; + } + for (MemberIsUsedEnum obj : EnumUtils.getEnumList(MemberIsUsedEnum.class)) { + if (obj.eqValue(value)) { + return obj; + } + } + return null; + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/error/ErrorCodeEnum.java b/wjcy-common/src/main/java/me/zhengjie/error/ErrorCodeEnum.java new file mode 100644 index 0000000..834a36e --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/error/ErrorCodeEnum.java @@ -0,0 +1,143 @@ +package me.zhengjie.error; + +import cn.hutool.core.convert.Convert; +import me.zhengjie.utils.PropertiesUtil; +import me.zhengjie.utils.RequestHolder; + +/** + *

+ * 返回错误枚举类型 + *

+ * + * @Author xx + * @Date 2021/7/19 + **/ +public enum ErrorCodeEnum { + RETURN_SUCCESS(200, "响应成功"), + UNKNOWN_ERROR(2000,"服务器开小差了....,请稍后再试!"), + BAD_CREDENTIALS(2001,"坏的凭证"), + ENTITY_EXIST(2003,"信息重复添加"), + ENTITY_NOT_FOUND(2004,"数据不存在"), + METHOD_ARGUMENT_NOT_VALID(2005,"数据验证失败异常"), + VALIDATION_ERROR(2006,"参数验证失败"), + HANDLE_BIND_ERROR(2007,"参数绑定失败"), + MESSAGE_NOT_READABLE(2008,"参数解析失败"), + MISSING_REQUEST_HEADER(2009,"缺少请求头参数"), + NO_HANDLER_FOUND(2010,"Not Found"), + METHOD_NOT_SUPPORTED(2011,"不支持当前请求方法"), + MEDIA_TYPE_NOT_SUPPORTED(2012,"不支持当前媒体类型"), + MAX_UPLOAD_SIZE_EXCEEDED(2013,"文件上传-文件大小超过限制"), + NO_PERMISSION_FOR_THIS_OPERATION(1328, "暂无权限"), + UPLOAD_IMG_FORMAT_ERROR(2015,"上传图片格式错误"), + REQUEST_PARAMS_NULL_ERROR(2016,"请求参数空值异常,请检查后重试!"), + SERVER_DESERTION_ERROR(2017,"服务器开小差了....,请稍后再试!"), + FORM_SUBMISSION_REPETITION_ERROR(1360, "操作过于频繁,请稍后再试"), + LOGIN_PWD_ERROR(2218, "密码错误!"), + BLOCKED_ACCOUNT_ERROR(2219, "多次输人错误的密码,账户已被冻结!"), + LOGIN_IP_FORMAT_ERROR(2220, "IP地址格式错误!"), + BLOCKED_LOGIN_IP_ERROR(2221, "非法IP!"), + ERROR_2222(2222, "验证码错误!"), + ERROR_2223(2223, "验证码不存在或已过期!"), + + // 业务 + // 买家 + ERROR_NOT_FIND_BUYER_USER(3000, "买家信息不存在!"), + ERROR_EXIST_FIND_BUYER_USER(3001, "买家信息已存在!"), + ERROR_NOT_UPDATE_EXIST_ORDER_BUYER_USER(3002, "买家存在订单信息,不允许修改token和平台信息"), + ERROR_NOT_DEL_EXIST_ORDER_BUYER_USER(3003, "买家存在订单信息,不允许删除"), + + + // EXCEL + ERROR_NOT_FIND_EXCEL_USER(3100, "卖家信息不存在!"), + + + // 平台 + ERROR_NOT_FIND_PLAT_USER(3200, "平台信息不存在!"), + ERROR_EXITS_COMPANY_INFO(3201,"该平台下存在公司,不允许删除!"), + + // 公司 + ERROR_NOT_FIND_COMPANY(3300, "公司信息不存在!"), + ERROR_EXITS_CT_ORDER_INFO(3201,"该公司下存在订单信息,不允许删除!"), + + // 信用卡 + ERROR_NOT_FIND_CARD_INFO(3300, "信用卡信息不存在,或者已删除或异常!"), + ERROR_NOT_FIND_CARD(3301, "信用卡信息不存在!"), + + //VPN + ERROR_NOT_FIND_VPN(3300, "VPN信息不存在,或者已删除!"), + + //影刀任务信息 + ERROR_NOT_FIND_JOB(3400,"影刀任务信息不存在,或者已删除"), + ERROR_NOT_FIND_TASK(3401,"影刀应用信息异常, 请检查后重试!"), + + //应用信息Apply + ERROR_NOT_FIND_APPLY(3500,"应用信息不存在,或者已删除"), + + //影刀机器人信息 rebot + ERROR_NOT_FIND_REBOT(3600,"机器人信息不存在,或者已删除"), + ERROR_NOT_FIND_OR_OCCUPY(3601, "机器人不存在,或者已占用"), + + // 影刀回调 + ERROR_PARAM_NULL(3700, "影刀回调参数空值异常!"), + ERROR_CALLBACK_SIGN_NULL(3701, "影刀回调鉴权异常!"), + + + // 敦煌支付 + ERROR_DH_PAY_NOT_FIND_OR_SUCCESS(3800,"敦煌支付信息不存在,或已删除!"), + + // 刷单流程 + ERROR_NOT_FIND_CLICKFARMING_INFO(3900, "刷单信息不存在!"), + ERROR_DEL_CLICKFARMING_INFO(3901, "只有待执行的刷单信息才允许删除!"), + ERROR_CLICKFARMING_NOT_TOBE(3902, "刷单信息非待执行状态,请检查后重新操作!"), + ERROR_CLICKFARMING_NOT_SUPPLEMENT(3903, "仅支付成功失败状态才允许补录!"), + ERROR_CLICK_ORDER_NOT_COMMENT(3904, "仅刷单成功状态,才拥有订单信息!"), + + // 订单信息 + ERROR_NOT_FIND_CLICK_ORDER_INFO(4100, "订单信息不存在"), + ERROR_NOT_NULL_ERP_AUTH_TOKEN(4101, "鉴权信息不能为空!"), + ERROR_ERP_AUTH_TOKEN(4102, "鉴权信息错误,请检查后重试!"), + + // 应用 + ERROR_NOT_REPEAT_ID(4200, "应用ID存在重复!"), + ERROR_NOT_FIND_METHOD_NAME(4201, "不存在对应方法名称!"), + + // 浏览信息不存在 + ERROR_NOT_FIND_BROWSE(4300, "浏览信息不存在!"), + + // 敦煌加购 + ERROR_ADD_CAR_KEY_NULL(4400, "关键词类型-商品关键词属性不能为空"), + ERROR_ADD_CAR_LINK_NULL(4401, "链接类型-商品关键词属性不能为空"), + ERROR_ADD_CAR_GOODS_NULL(4403, "商品属性不能为空"), + ERROR_NOT_FIND_ADD_CAR_INFO(4404, "敦煌加购信息不存在,或者已删除或异常!"), + ERROR_DEL_ADD_CAR_INFO(4405, "只有待执行的刷单信息才允许删除!"), + ERROR_NOT_EDIT_ADD_CAR_INFO(4406, "敦煌加购信息仅带执行才允许修改!"), + ERROR_NOT_WELL_RECEIVED_ADD_CAR_INFO(4407, "敦煌加购信息仅抓单成功才允许评论!"); + + private int code; + + private String desc; + /** 初始化 */ + ErrorCodeEnum(int code, String desc) { + this.code = code; + this.desc = desc; + } + /** 获取错误状态码 */ + public int getCode() { + return code; + } + /** 设置错误状态码 */ + public void setCode(int code) { + this.code = code; + } + /** 获取错误描述 */ + public String getDesc() { +// String language = RequestHolder.getLanguage(); +// String message = Convert.toStr(PropertiesUtil.getByCode(code, language), desc); + return desc; + } + /** 设置错误描述 */ + public void setDesc(String desc) { + this.desc = desc; + } + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/exception/BadConfigurationException.java b/wjcy-common/src/main/java/me/zhengjie/exception/BadConfigurationException.java new file mode 100644 index 0000000..ede3691 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/exception/BadConfigurationException.java @@ -0,0 +1,98 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.exception; + +/** + * 统一关于错误配置信息 异常 + * + * @author: liaojinlong + * @date: 2020/6/10 18:06 + */ +public class BadConfigurationException extends RuntimeException { + /** + * Constructs a new runtime exception with {@code null} as its + * detail message. The cause is not initialized, and may subsequently be + * initialized by a call to {@link #initCause}. + */ + public BadConfigurationException() { + super(); + } + + /** + * Constructs a new runtime exception with the specified detail message. + * The cause is not initialized, and may subsequently be initialized by a + * call to {@link #initCause}. + * + * @param message the detail message. The detail message is saved for + * later retrieval by the {@link #getMessage()} method. + */ + public BadConfigurationException(String message) { + super(message); + } + + /** + * Constructs a new runtime exception with the specified detail message and + * cause.

Note that the detail message associated with + * {@code cause} is not automatically incorporated in + * this runtime exception's detail message. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A {@code null} value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 1.4 + */ + public BadConfigurationException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new runtime exception with the specified cause and a + * detail message of {@code (cause==null ? null : cause.toString())} + * (which typically contains the class and detail message of + * {@code cause}). This constructor is useful for runtime exceptions + * that are little more than wrappers for other throwables. + * + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A {@code null} value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 1.4 + */ + public BadConfigurationException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new runtime exception with the specified detail + * message, cause, suppression enabled or disabled, and writable + * stack trace enabled or disabled. + * + * @param message the detail message. + * @param cause the cause. (A {@code null} value is permitted, + * and indicates that the cause is nonexistent or unknown.) + * @param enableSuppression whether or not suppression is enabled + * or disabled + * @param writableStackTrace whether or not the stack trace should + * be writable + * @since 1.7 + */ + protected BadConfigurationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/exception/BadRequestException.java b/wjcy-common/src/main/java/me/zhengjie/exception/BadRequestException.java new file mode 100644 index 0000000..3501adc --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/exception/BadRequestException.java @@ -0,0 +1,50 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.exception; + +import lombok.Getter; +import me.zhengjie.error.ErrorCodeEnum; +import org.springframework.http.HttpStatus; +import static org.springframework.http.HttpStatus.BAD_REQUEST; + +/** + * @author Zheng Jie + * @date 2018-11-23 + * 统一异常处理 + */ +@Getter +public class BadRequestException extends RuntimeException{ + + + private Integer status = BAD_REQUEST.value(); + + public BadRequestException(String msg){ + super(msg); + } + + public BadRequestException(HttpStatus status,String msg){ + super(msg); + this.status = status.value(); + } + public BadRequestException(Integer status,String msg){ + super(msg); + this.status = status; + } + public BadRequestException(ErrorCodeEnum errorCodeEnum){ + super(errorCodeEnum.getDesc()); + this.status = errorCodeEnum.getCode(); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/exception/EntityExistException.java b/wjcy-common/src/main/java/me/zhengjie/exception/EntityExistException.java new file mode 100644 index 0000000..03f9bf2 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/exception/EntityExistException.java @@ -0,0 +1,34 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.exception; + +import org.springframework.util.StringUtils; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +public class EntityExistException extends RuntimeException { + + public EntityExistException(Class clazz, String field, String val) { + super(EntityExistException.generateMessage(clazz.getSimpleName(), field, val)); + } + + private static String generateMessage(String entity, String field, String val) { + return StringUtils.capitalize(entity) + + " with " + field + " "+ val + " existed"; + } +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/exception/EntityNotFoundException.java b/wjcy-common/src/main/java/me/zhengjie/exception/EntityNotFoundException.java new file mode 100644 index 0000000..bcdc956 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/exception/EntityNotFoundException.java @@ -0,0 +1,34 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.exception; + +import org.springframework.util.StringUtils; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +public class EntityNotFoundException extends RuntimeException { + + public EntityNotFoundException(Class clazz, String field, String val) { + super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), field, val)); + } + + private static String generateMessage(String entity, String field, String val) { + return StringUtils.capitalize(entity) + + " with " + field + " "+ val + " does not exist"; + } +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/exception/handler/ApiError.java b/wjcy-common/src/main/java/me/zhengjie/exception/handler/ApiError.java new file mode 100644 index 0000000..5112730 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/exception/handler/ApiError.java @@ -0,0 +1,52 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.exception.handler; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import java.time.LocalDateTime; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Data +class ApiError { + + private Integer status = 400; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime timestamp; + private String message; + + private ApiError() { + timestamp = LocalDateTime.now(); + } + + public static ApiError error(String message){ + ApiError apiError = new ApiError(); + apiError.setMessage(message); + return apiError; + } + + public static ApiError error(Integer status, String message){ + ApiError apiError = new ApiError(); + apiError.setStatus(status); + apiError.setMessage(message); + return apiError; + } +} + + diff --git a/wjcy-common/src/main/java/me/zhengjie/exception/handler/GlobalExceptionHandler.java b/wjcy-common/src/main/java/me/zhengjie/exception/handler/GlobalExceptionHandler.java new file mode 100644 index 0000000..4561bae --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/exception/handler/GlobalExceptionHandler.java @@ -0,0 +1,197 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.exception.handler; + +import cn.hutool.core.util.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.dto.Dto; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.exception.EntityExistException; +import me.zhengjie.exception.EntityNotFoundException; +import me.zhengjie.utils.ThrowableUtil; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.validation.BindException; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; +import org.springframework.web.HttpMediaTypeNotSupportedException; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingRequestHeaderException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.multipart.MaxUploadSizeExceededException; +import org.springframework.web.servlet.NoHandlerFoundException; + +import javax.annotation.Resource; +import javax.validation.ValidationException; +import java.util.List; + +import static me.zhengjie.error.ErrorCodeEnum.*; +import static me.zhengjie.error.ErrorCodeEnum.MAX_UPLOAD_SIZE_EXCEEDED; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + /** + * 不允许访问的异常 + */ + @ExceptionHandler(AccessDeniedException.class) + public Dto accessDeniedException(Throwable e) { + // 打印堆栈信息 + log.error(NO_PERMISSION_FOR_THIS_OPERATION.getCode()+ThrowableUtil.getStackTrace(e)); + return Dto.getInstance(NO_PERMISSION_FOR_THIS_OPERATION); + } + + /** + * 处理所有不可知的异常 + */ + @ExceptionHandler(Throwable.class) + public Dto handleException(Throwable e) { + // 打印堆栈信息 + log.error(UNKNOWN_ERROR.getCode()+ThrowableUtil.getStackTrace(e)); + return Dto.getInstance(UNKNOWN_ERROR); + } + + /** + * BadCredentialsException + */ + @ExceptionHandler(BadCredentialsException.class) + public Dto badCredentialsException(BadCredentialsException e) { + // 打印堆栈信息 + log.error(BAD_CREDENTIALS.getCode()+ThrowableUtil.getStackTrace(e)); + return Dto.getInstance(BAD_CREDENTIALS); + } + + /** + * 处理自定义异常 + */ + @ExceptionHandler(value = BadRequestException.class) + public Dto badRequestException(BadRequestException e) { + // 打印堆栈信息 + log.error(e.getStatus()+ThrowableUtil.getStackTrace(e)); + Dto dto = Dto.returnResult(false); + dto.setCode(e.getStatus()); + dto.setMessage(e.getMessage()); + return dto; + } + + /** + * 处理 EntityExist + */ + @ExceptionHandler(value = EntityExistException.class) + public Dto entityExistException(EntityExistException e) { + // 打印堆栈信息 + log.error(ENTITY_EXIST.getCode()+ThrowableUtil.getStackTrace(e)); + return Dto.getInstance(ENTITY_EXIST); + } + + /** + * 处理 EntityNotFound + */ + @ExceptionHandler(value = EntityNotFoundException.class) + public Dto entityNotFoundException(EntityNotFoundException e) { + // 打印堆栈信息 + log.error(ENTITY_NOT_FOUND.getCode()+ThrowableUtil.getStackTrace(e)); + return Dto.getInstance(ENTITY_NOT_FOUND); + } + + /** + * 处理所有接口数据验证异常 + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + public Dto handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { + // 打印堆栈信息 + log.error(ThrowableUtil.getStackTrace(e)); + StringBuffer sbf = new StringBuffer(); + List allErrors = e.getBindingResult().getAllErrors(); + for (ObjectError allError : allErrors) { + if (allError instanceof FieldError) { + FieldError fieldError = (FieldError)allError; + sbf.append("["+fieldError.getField() + ":" + fieldError.getDefaultMessage() + "] "); + } + } + Dto dto = Dto.getInstance(METHOD_ARGUMENT_NOT_VALID); + if (ObjectUtil.isNotEmpty(sbf)) { + dto.setMessage(sbf.toString()); + } + return dto; + } + + @ExceptionHandler(ValidationException.class) + @ResponseBody + public Dto handleValidationException(ValidationException e) { + log.error(VALIDATION_ERROR.getCode()+ThrowableUtil.getStackTrace(e)); + return Dto.getInstance(VALIDATION_ERROR); + } + + @ExceptionHandler(BindException.class) + @ResponseBody + public Dto handleBindException(BindException e) { + log.error(HANDLE_BIND_ERROR.getCode()+ThrowableUtil.getStackTrace(e)); + return Dto.getInstance(HANDLE_BIND_ERROR); + } + + @ExceptionHandler(HttpMessageNotReadableException.class) + @ResponseBody + public Dto handleHttpMessageNotReadableException(HttpMessageNotReadableException e) { + log.error(MESSAGE_NOT_READABLE.getCode()+ThrowableUtil.getStackTrace(e)); + return Dto.getInstance(MESSAGE_NOT_READABLE); + } + + @ExceptionHandler(MissingRequestHeaderException.class) + @ResponseBody + public Dto missingRequestHeaderException(MissingRequestHeaderException e) { + log.error(MISSING_REQUEST_HEADER.getCode()+ThrowableUtil.getStackTrace(e)); + return Dto.getInstance(MISSING_REQUEST_HEADER); + } + + @ExceptionHandler(NoHandlerFoundException.class) + @ResponseBody + public Dto noHandlerFoundException(NoHandlerFoundException e) { + log.error(NO_HANDLER_FOUND.getCode()+ThrowableUtil.getStackTrace(e)); + return Dto.getInstance(NO_HANDLER_FOUND); + } + + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + @ResponseBody + public Dto handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) { + log.error(METHOD_NOT_SUPPORTED.getCode()+ThrowableUtil.getStackTrace(e)); + return Dto.getInstance(METHOD_NOT_SUPPORTED); + } + + @ExceptionHandler(HttpMediaTypeNotSupportedException.class) + @ResponseBody + public Dto handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) { + log.error(MEDIA_TYPE_NOT_SUPPORTED.getCode()+ThrowableUtil.getStackTrace(e)); + return Dto.getInstance(MEDIA_TYPE_NOT_SUPPORTED); + } + + @ExceptionHandler(value = MaxUploadSizeExceededException.class) + @ResponseBody + public Dto maxUploadSizeExceededException(MaxUploadSizeExceededException e) { + log.error(MAX_UPLOAD_SIZE_EXCEEDED.getCode()+ThrowableUtil.getStackTrace(e)); + return Dto.getInstance(MAX_UPLOAD_SIZE_EXCEEDED); + } + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/mybatis/LambdaQueryWrapperImpl.java b/wjcy-common/src/main/java/me/zhengjie/mybatis/LambdaQueryWrapperImpl.java new file mode 100644 index 0000000..d1911cb --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/mybatis/LambdaQueryWrapperImpl.java @@ -0,0 +1,29 @@ +package me.zhengjie.mybatis; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; + +/* + * + * @Description + * @Date 2021/12/6 + * @Author zeng + */ +public class LambdaQueryWrapperImpl extends LambdaQueryWrapper { + + private String name; + + @Override + public String getCustomSqlSegment() { + String customSqlSegment = super.getCustomSqlSegment(); + if (ObjectUtil.isNotEmpty(name)) { + customSqlSegment = customSqlSegment.replaceAll("ew.", name + "."); + } + return customSqlSegment; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/CtApplyService.java b/wjcy-common/src/main/java/me/zhengjie/service/CtApplyService.java new file mode 100644 index 0000000..c67a12d --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/CtApplyService.java @@ -0,0 +1,42 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.CtApply; +import me.zhengjie.service.vo.CtApplyListVO; +import me.zhengjie.utils.PageUtils; + +import java.util.List; + +/** + * 影刀应用信息(CtApply)表服务接口 + * + * @author rch + * @since 2022-07-23 + */ +public interface CtApplyService extends IService { + + /** + * 分页查询 + * @param page + * @param ew + * @return PageUtils + */ + PageUtils searchPageList(IPage page, Wrapper ew); + + /** + * 查询所有应用信息 + * @return LIST + */ + List getAllApplyName(); + + /** + * 根据方法应用对应的TaskName和Method查询应用信息 + * @param taskName + * @param method + * @return + */ + CtApply getApplyByTaskAndMethod(String taskName, String method); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/CtBrowseService.java b/wjcy-common/src/main/java/me/zhengjie/service/CtBrowseService.java new file mode 100644 index 0000000..b0b8401 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/CtBrowseService.java @@ -0,0 +1,41 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.CtBrowse; +import me.zhengjie.service.vo.CtBrowseDetailVO; +import me.zhengjie.service.vo.CtBrowseListVO; +import me.zhengjie.utils.PageUtils; + +/** + * 浏览收藏(CtBrowse)表服务接口 + * + * @author rch + * @since 2022-11-04 09:45:32 + */ +public interface CtBrowseService extends IService { + + /** + * 分页查询 + * @param page + * @param ew + * @return + */ + PageUtils searchPageList(IPage page, Wrapper ew); + + /** + * 获取好评刷单信息-加锁 + * @param id + * @return + */ + CtBrowse getByIdLock(Long id); + + /** + * 根据id获取详情 + * @param id + * @return + */ + CtBrowseDetailVO getBrowseDetailById(Long id); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/CtBuyerService.java b/wjcy-common/src/main/java/me/zhengjie/service/CtBuyerService.java new file mode 100644 index 0000000..b6c71d9 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/CtBuyerService.java @@ -0,0 +1,50 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.CtBuyer; +import me.zhengjie.service.vo.CtBuyerDetailVO; +import me.zhengjie.service.vo.CtBuyerListVO; +import me.zhengjie.utils.PageUtils; + +import java.util.List; +import java.util.Map; + +/** + * 买家表(CtBuyer)表服务接口 + * + * @author rch + * @since 2022-06-22 + */ +public interface CtBuyerService extends IService { + + /** + * 分页查询买家信息 + * @param page + * @param ew + * @return + */ + PageUtils searchPageList(IPage page, Wrapper ew); + + /** + * 根据Id获取详情信息 + * @param id + * @return + */ + CtBuyerDetailVO getDetailById(Long id); + + List getAllAccount(); + + String getPwdByName(String name); + + CtBuyer getBuyerOccupyStatusLock(String buyerName); + + /** + * 根据买家账号 返回存在的买家信息 + * @param buyerAccountList + * @return + */ + Map getBuyerList(List buyerAccountList); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/CtCardService.java b/wjcy-common/src/main/java/me/zhengjie/service/CtCardService.java new file mode 100644 index 0000000..6727e2e --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/CtCardService.java @@ -0,0 +1,26 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.CtCard; +import me.zhengjie.entity.CtCardInfo; + +import java.util.List; + +/** + * 信用卡信息(CtCard)表服务接口 + * + * @author rch + * @since 2022-07-07 + */ +public interface CtCardService extends IService { + + List getNumberList(); + + /** + * 根据信用卡号查询信用卡信息 + * @param number + * @return ctCardInfo(id,number) + */ + List getCardInfoByNumber(List number); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/CtClickFarmingService.java b/wjcy-common/src/main/java/me/zhengjie/service/CtClickFarmingService.java new file mode 100644 index 0000000..f88d31f --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/CtClickFarmingService.java @@ -0,0 +1,36 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.CtBuyerClickSuccess; +import me.zhengjie.entity.CtClickFarmYdParams; +import me.zhengjie.entity.CtClickFarming; +import me.zhengjie.service.vo.CtClickFarmEditDetailVO; +import me.zhengjie.service.vo.CtClickFarmingDetailVO; +import me.zhengjie.service.vo.CtClickFarmingVO; +import me.zhengjie.utils.PageUtils; + +import java.util.List; + +/** + * 刷单Excel信息(CtClickFarming)表服务接口 + * + * @author rch + * @since 2022-08-16 + */ +public interface CtClickFarmingService extends IService { + + PageUtils searchPageList(IPage page, Wrapper ew); + + CtClickFarming getByIdLock(Long id); + + CtClickFarmEditDetailVO getEditDetailById(Long id); + + CtClickFarmingDetailVO getDetailById(Long id); + + List ruleGetCtBuyer(String buyerAccount, String country, String shopName); + + CtClickFarmYdParams getCtClickFarmYdParams(Long valueOf); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/CtClickOrderService.java b/wjcy-common/src/main/java/me/zhengjie/service/CtClickOrderService.java new file mode 100644 index 0000000..30b471c --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/CtClickOrderService.java @@ -0,0 +1,65 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.CtClickFarmingOrderInfo; +import me.zhengjie.entity.CtClickOrder; +import me.zhengjie.service.vo.CtClickOrderDetailVO; +import me.zhengjie.service.vo.CtClickOrderListVO; +import me.zhengjie.utils.PageUtils; + +import java.util.List; + +/** + * 刷单-订单信息(CtClickOrder)表服务接口 + * + * @author rch + * @since 2022-09-14 + */ +public interface CtClickOrderService extends IService { + + /** + * 返回实际存在的订单id + * @param importOrderIdList + * @return + */ + List getOrderId(List importOrderIdList); + + /** + * 分页查询 + * @param page + * @param ew + * @return + */ + PageUtils searchPageList(IPage page, Wrapper ew); + + /** + * 手动补录刷单信息对应的订单信息 + * @param clickFarmingId + * @param ctClickOrder + */ + Boolean supplement(Long clickFarmingId, CtClickOrder ctClickOrder); + + /** + * 根据订单id 获取刷单订单详情信息 + * @param orderId + * @return + */ + CtClickFarmingOrderInfo getClickFarmOrderById(Long orderId); + + /** + * 悲观锁根据id获取刷单订单信息 + * @param valueOf + * @return + */ + CtClickOrder getByIdLock(Long valueOf); + + /** + * 根据订单Id获取订单详情 + * @param id + * @return + */ + CtClickOrderDetailVO getClickOrderDetailById(Long id); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/CtCompanyService.java b/wjcy-common/src/main/java/me/zhengjie/service/CtCompanyService.java new file mode 100644 index 0000000..10d4c04 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/CtCompanyService.java @@ -0,0 +1,34 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.CtCompany; +import me.zhengjie.entity.CtCompanyInfo; + +import java.util.List; +import java.util.Map; + +/** + * 公司信息(CtCompany)表服务接口 + * + * @author makejava + * @since 2022-06-23 10:37:44 + */ +public interface CtCompanyService extends IService { + + /** + * 根据公司名字 获取公司信息 + * @param name + * @return + */ + List getByNmae(List name); + + List getCompanyList(); + + /** + * 根据名称返回存在的公司信息 Map形式 key:id value:公司名称 + * @param platNameList + * @return + */ + Map getNameList(List platNameList); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/CtDhPayService.java b/wjcy-common/src/main/java/me/zhengjie/service/CtDhPayService.java new file mode 100644 index 0000000..22612f4 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/CtDhPayService.java @@ -0,0 +1,29 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.CtDhPay; +import me.zhengjie.service.vo.CtDhPayListVO; +import me.zhengjie.utils.PageUtils; + +/** + * 平台信息(CtDyPay)表服务接口 + * + * @author rch + * @since 2022-07-28 + */ +public interface CtDhPayService extends IService { + + PageUtils searchPageList(IPage page, Wrapper ew); + + void toPay(); + + /** + * 调用支付接口 + * @param ctDhPay + * @return + */ + public Boolean payOrderApi(CtDhPay ctDhPay); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/CtExcelImportInfoService.java b/wjcy-common/src/main/java/me/zhengjie/service/CtExcelImportInfoService.java new file mode 100644 index 0000000..9f2ba5a --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/CtExcelImportInfoService.java @@ -0,0 +1,23 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.CtExcelImportInfo; + +import java.io.IOException; + +/** + * Excel导入信息(CtExcelImportInfo)表服务接口 + * + * @author rch + * @since 2022-06-23 + */ +public interface CtExcelImportInfoService extends IService { + + /** + * Excel 数据导入Mysql + * + * TODO 先做一版批量导入的,如果导入过程错误先不考虑 + */ + void importExcel() throws IOException; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/CtExcelService.java b/wjcy-common/src/main/java/me/zhengjie/service/CtExcelService.java new file mode 100644 index 0000000..a3d470b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/CtExcelService.java @@ -0,0 +1,15 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.CtExcel; + +/** + * Excel 导入信息(CtExcel)表服务接口 + * + * @author makejava + * @since 2022-06-23 10:37:44 + */ +public interface CtExcelService extends IService { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/CtOrderService.java b/wjcy-common/src/main/java/me/zhengjie/service/CtOrderService.java new file mode 100644 index 0000000..0bba1ec --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/CtOrderService.java @@ -0,0 +1,31 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.CtExcelImportInfo; +import me.zhengjie.entity.CtOrder; +import org.springframework.stereotype.Service; + +/** + * (CtOrder)表服务接口 + * + * @author rch + * @since 2022-07-01 + */ +@Service +public interface CtOrderService extends IService { + + /** + * Excel 数据转换存储到订单表里 Order 一对多 + */ + void excelToOrder(); + + Boolean buyOrderApi(CtExcelImportInfo ctExcelImportInfo); + + /** + * 订单支付 + */ + void toPay(); + + Boolean payOrderApi(CtOrder ctOrder); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/CtPlatformService.java b/wjcy-common/src/main/java/me/zhengjie/service/CtPlatformService.java new file mode 100644 index 0000000..37611dd --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/CtPlatformService.java @@ -0,0 +1,24 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.CtPlatform; + +import java.util.List; +import java.util.Map; + +/** + * 平台信息(CtPlatform)表服务接口 + * + * @author makejava + * @since 2022-06-23 10:37:44 + */ +public interface CtPlatformService extends IService { + + /** + * 返回存在的对应名称的平台信息名称 + * @param platNameList + * @return + */ + Map getNameList(List platNameList); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/CtRebotService.java b/wjcy-common/src/main/java/me/zhengjie/service/CtRebotService.java new file mode 100644 index 0000000..b784caf --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/CtRebotService.java @@ -0,0 +1,63 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.CtRebot; +import me.zhengjie.service.vo.CtRebotListVO; +import me.zhengjie.utils.PageUtils; +import org.springframework.data.convert.JodaTimeConverters; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 影刀设备-机器人信息(CtRebot)表服务接口 + * + * @author rch + * @since 2022-07-23 + */ +public interface CtRebotService extends IService { + + CtRebot getByAccountNameLock(String accountName); + + /** + * 分页查询 影刀机器人信息 + * @param page + * @param wr + * @return PageUtils + */ + PageUtils searchPageList(IPage page, Wrapper wr); + + /** + * excel导入机器人信息 + * @param file + * @param response + * @return Dto + */ + Dto importRebot(MultipartFile file, HttpServletResponse response) throws Exception; + + /** + * 获取所有机器人名称 + * @return LIST + */ + List getAccountNameList(); + + /** + * 获取所有uuid信息 + * @return LIST + */ + List getClientUuidList(); + + /** + * 根据id和老状态 修改新状态 + * @param id + * @param newStatus + * @param oldStatus + * @return + */ + Boolean updateNewStatusByOldStatus(Long id, Integer newStatus, Integer oldStatus); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/CtResponseOrderAddressService.java b/wjcy-common/src/main/java/me/zhengjie/service/CtResponseOrderAddressService.java new file mode 100644 index 0000000..c639064 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/CtResponseOrderAddressService.java @@ -0,0 +1,17 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.CtResponseOrderAddress; +import org.springframework.stereotype.Service; + +/** + * 下注成功订单响应收货地址信息(CtResponseOrderAddress)表服务接口 + * + * @author rch + * @since 2022-07-01 + */ +@Service +public interface CtResponseOrderAddressService extends IService { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/CtResponseOrderProductService.java b/wjcy-common/src/main/java/me/zhengjie/service/CtResponseOrderProductService.java new file mode 100644 index 0000000..956fb20 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/CtResponseOrderProductService.java @@ -0,0 +1,17 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.CtResponseOrderProduct; +import org.springframework.stereotype.Service; + +/** + * 下单订单响应产品信息(CtResponseOrderProduct)表服务接口 + * + * @author rch + * @since 2022-07-01 + */ +@Service +public interface CtResponseOrderProductService extends IService { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/CtResponseOrderService.java b/wjcy-common/src/main/java/me/zhengjie/service/CtResponseOrderService.java new file mode 100644 index 0000000..99d8a84 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/CtResponseOrderService.java @@ -0,0 +1,17 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.CtResponseOrder; +import org.springframework.stereotype.Service; + +/** + * 下单成功响应订单商品信息(CtResponseOrder)表服务接口 + * + * @author rch + * @since 2022-07-01 + */ +@Service +public interface CtResponseOrderService extends IService { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/CtVpnService.java b/wjcy-common/src/main/java/me/zhengjie/service/CtVpnService.java new file mode 100644 index 0000000..d4327c2 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/CtVpnService.java @@ -0,0 +1,24 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.CtVpn; +import me.zhengjie.entity.CtVpnInfo; + +import java.util.List; + +/** + * VPN信息表(CtVpn)表服务接口 + * + * @author rch + * @since 2022-07-07 + */ +public interface CtVpnService extends IService { + + List getIpList(); + + /** + * 根据ip地址查询vpn信息(id、ip地址) + */ + List getVpnInfoByIp(List ipAddress); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/DhAddCarOrderService.java b/wjcy-common/src/main/java/me/zhengjie/service/DhAddCarOrderService.java new file mode 100644 index 0000000..861fc33 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/DhAddCarOrderService.java @@ -0,0 +1,41 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.DhAddCarOrder; +import me.zhengjie.service.vo.dhcarorder.DhAddCarOrderListVO; +import me.zhengjie.service.vo.dhcarorder.DhCarOrderParamsVO; +import me.zhengjie.utils.PageUtils; + +/** + * 敦煌-加购物车-订单(DhAddCarOrder)表服务接口 + * + * @author rch + * @since 2022-11-17 09:11:59 + */ +public interface DhAddCarOrderService extends IService { + + /** + * 加锁获取敦煌购物车抓单信息 + * @param valueOf + * @return + */ + DhAddCarOrder getByIdLock(Long valueOf); + + /** + * 分页查询 + * @param page + * @param ew + * @return + */ + PageUtils searchPageList(IPage page, Wrapper ew); + + /** + * 获取敦煌加购-好评影刀参数 + * @param valueOf + * @return + */ + DhCarOrderParamsVO getYdParams(Long valueOf); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/DhAddCarService.java b/wjcy-common/src/main/java/me/zhengjie/service/DhAddCarService.java new file mode 100644 index 0000000..59c02b5 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/DhAddCarService.java @@ -0,0 +1,49 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.DhAddCar; +import me.zhengjie.service.vo.dhaddcar.DhAddCarVO; +import me.zhengjie.service.vo.dhaddcar.DhAddCarListVO; +import me.zhengjie.service.vo.dhaddcar.DhAddCarYdParamsVO; +import me.zhengjie.utils.PageUtils; + +/** + * 敦煌加入购物车(DhAddCar)表服务接口 + * + * @author makejava + * @since 2022-11-17 09:11:55 + */ +public interface DhAddCarService extends IService { + + /** + * 分页查询 + * @param page + * @param ew + * @return + */ + PageUtils searchPageList(IPage page, Wrapper ew); + + /** + * 根据id获取加购信息 + * @param id + * @return + */ + DhAddCarVO getDetailById(Long id); + + /** + * 根据id加悲观锁查询 + * @param id + * @return + */ + DhAddCar getByIdLock(Long id); + + /** + * 拼接影刀参数 + * @param id + * @return + */ + DhAddCarYdParamsVO getAddCarYdParams(Long id); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/DhCarGoodsService.java b/wjcy-common/src/main/java/me/zhengjie/service/DhCarGoodsService.java new file mode 100644 index 0000000..7546ef4 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/DhCarGoodsService.java @@ -0,0 +1,15 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.DhCarGoods; + +/** + * 敦煌-加入购物车商品信息(DhCarGoods)表服务接口 + * + * @author makejava + * @since 2022-11-17 09:12:03 + */ +public interface DhCarGoodsService extends IService { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/FileUploadService.java b/wjcy-common/src/main/java/me/zhengjie/service/FileUploadService.java new file mode 100644 index 0000000..e7af6ee --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/FileUploadService.java @@ -0,0 +1,20 @@ +package me.zhengjie.service; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; + +/** + *

+ * 图片上传服务 + *

+ * + * @Author xx + * @Date 2021/7/26 + **/ +public interface FileUploadService { + + List uploadify(HttpServletRequest request, HttpServletResponse response) + throws IOException; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/LoginIpService.java b/wjcy-common/src/main/java/me/zhengjie/service/LoginIpService.java new file mode 100644 index 0000000..a0bfcad --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/LoginIpService.java @@ -0,0 +1,58 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.LoginIp; +import me.zhengjie.utils.PageUtils; + +import java.util.List; + +/** + * (LoginIp)表服务接口 + * + * @author zeng + * @since 2022-03-21 14:07:01 + */ +public interface LoginIpService extends IService { + + String LOGIN_IP_LIST = "LOGIN_IP_LIST"; + + /** + * 获取IP列表 + * @author: zeng + * @param iPage + */ + PageUtils getList(IPage iPage); + + /** + * 新增 + * @author: zeng + */ + boolean addIp(LoginIp ip); + + /** + * 查询所有有效白名单IP段 + * @return + */ + List getAll(); + + /** + * 编辑 + * @author: zeng + */ + boolean updateIp(LoginIp ip); + + /** + * 删除 + * @author: zeng + */ + boolean deleteIp(Integer id); + + /** + * 是否是白名单 + * @author: zeng + */ + boolean whiteListFlag(String ip); + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/SettingSiteService.java b/wjcy-common/src/main/java/me/zhengjie/service/SettingSiteService.java new file mode 100644 index 0000000..a3a2097 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/SettingSiteService.java @@ -0,0 +1,25 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.CtSettingSite; + +/** + * 站点配置(CtSettingSite)表服务接口 + * + * @author xxs + * @since 2021-11-17 + */ +public interface SettingSiteService extends IService { + + String getValue(String key); + + boolean saveOrUpdateByKey(String key, String value); + + /** + * Google认证器开关 + * @auth xxs + * @return + */ + Boolean getGooleAuthSwitch(); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/SysQuartzLogService.java b/wjcy-common/src/main/java/me/zhengjie/service/SysQuartzLogService.java new file mode 100644 index 0000000..0b56c21 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/SysQuartzLogService.java @@ -0,0 +1,21 @@ +package me.zhengjie.service; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.entity.SysQuartzJob; +import me.zhengjie.entity.SysQuartzLog; +import me.zhengjie.service.vo.SysQuartzLogListVO; +import me.zhengjie.utils.PageUtils; + +/** + * 定时任务(SysQuartzJob)表服务接口 + * + * @author rch + * @since 2022-07-20 + */ +public interface SysQuartzLogService extends IService { + + PageUtils searchPageList(IPage page, Wrapper wrapper); +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/YdQuartzService.java b/wjcy-common/src/main/java/me/zhengjie/service/YdQuartzService.java new file mode 100644 index 0000000..619bdf5 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/YdQuartzService.java @@ -0,0 +1,74 @@ +package me.zhengjie.service; + +import me.zhengjie.entity.quartz.JobQueryByUuidReturn; +import me.zhengjie.service.redission.LockCallBack; + +/** + * 影刀定时任务Service + * + * @author rch + * @since 2022-08-01 + */ +public interface YdQuartzService{ + + Object executeOnLock(String lockKey, long time, long timeout, LockCallBack callBack) throws Exception; + + public String exec(String str) throws Exception; + + + /** + * 刷单 任务执行逻辑 + * @param str + * @return + * @throws Exception + */ + public Boolean clickFarmExec(String str) throws Exception; + + /** + * 敦煌加购 任务执行逻辑 + * @param str + * @return + * @throws Exception + */ + public Boolean addCarExec(String str) throws Exception; + + + /** + * 敦煌-加购-抓单 + * @param str + * @return + * @throws Exception + */ + public Boolean catchOrderExec(String str) throws Exception; + + public JobQueryByUuidReturn queryJobUuid(String uuid, String accessKeyId, String accessKeySecret); + + /** + * 刷单任务-补录(有订单信息-支付失败) + * @param str + * @return + */ + Boolean clickFarmSuppleMentExec(String str) throws Exception; + + /** + * 敦煌 + * @param str + * @return + * @throws Exception + */ + public Object dhWellReceivedExec(String str) throws Exception; + /** + * 好评 + * @param str + * @return + */ + Object wellReceivedExec(String str) throws Exception; + + /** + * 浏览收藏 + * @param str + * @return + */ + Object browseTaskExec(String str) throws Exception; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/CtApplyServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtApplyServiceImpl.java new file mode 100644 index 0000000..c0b0190 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtApplyServiceImpl.java @@ -0,0 +1,44 @@ +package me.zhengjie.service.impl; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.dao.CtApplyDao; +import me.zhengjie.entity.CtApply; +import me.zhengjie.service.CtApplyService; +import me.zhengjie.service.vo.CtApplyListVO; +import me.zhengjie.utils.PageUtils; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 影刀应用信息(CtApply)表服务实现类 + * + * @author rch + * @since 2022-07-23 + */ +@Service +public class CtApplyServiceImpl extends ServiceImpl implements CtApplyService { + + @Resource + private CtApplyDao ctApplyDao; + + @Override + public PageUtils searchPageList(IPage page, Wrapper ew) { + ctApplyDao.searchPageList(page, ew); + return new PageUtils<>(page.getTotal(),page.getRecords()); + } + + @Override + public List getAllApplyName() { + return ctApplyDao.getAllApplyName(); + } + + @Override + public CtApply getApplyByTaskAndMethod(String taskName, String method) { + return ctApplyDao.getApplyByTaskAndMethod(taskName, method); + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/CtBrowseServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtBrowseServiceImpl.java new file mode 100644 index 0000000..2b7896d --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtBrowseServiceImpl.java @@ -0,0 +1,44 @@ +package me.zhengjie.service.impl; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.dao.CtBrowseDao; +import me.zhengjie.entity.CtBrowse; +import me.zhengjie.service.CtBrowseService; +import me.zhengjie.service.vo.CtBrowseDetailVO; +import me.zhengjie.service.vo.CtBrowseListVO; +import me.zhengjie.utils.PageUtils; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * 浏览收藏(CtBrowse)表服务实现类 + * + * @author rch + * @since 2022-11-04 09:45:33 + */ +@Service +public class CtBrowseServiceImpl extends ServiceImpl implements CtBrowseService { + + @Resource + private CtBrowseDao ctBrowseDao; + + @Override + public PageUtils searchPageList(IPage page, Wrapper ew) { + ctBrowseDao.searchPageList(page, ew); + return new PageUtils(page.getTotal(), page.getRecords()); + } + + @Override + public CtBrowse getByIdLock(Long id) { + return ctBrowseDao.getByIdLock(id); + } + + @Override + public CtBrowseDetailVO getBrowseDetailById(Long id) { + return ctBrowseDao.getBrowseDetailById(id); + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/CtBuyerServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtBuyerServiceImpl.java new file mode 100644 index 0000000..889a0ca --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtBuyerServiceImpl.java @@ -0,0 +1,69 @@ +package me.zhengjie.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.dao.CtBuyerDao; +import me.zhengjie.entity.CtBuyer; +import me.zhengjie.service.CtBuyerService; +import me.zhengjie.service.vo.CtBuyerDetailVO; +import me.zhengjie.service.vo.CtBuyerListVO; +import me.zhengjie.utils.PageUtils; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 买家表(CtBuyer)表服务实现类 + * + * @author rch + * @since 2022-06-22 + */ +@Service +public class CtBuyerServiceImpl extends ServiceImpl implements CtBuyerService { + + @Resource + private CtBuyerDao ctBuyerDao; + + @Override + public PageUtils searchPageList(IPage page, Wrapper ew) { + ctBuyerDao.searchPageList(page, ew); + return new PageUtils(page.getTotal(), page.getRecords()); + } + + @Override + public CtBuyerDetailVO getDetailById(Long id) { + return ctBuyerDao.getDetailById(id); + } + + @Override + public List getAllAccount(){ return ctBuyerDao.getAllAccount();} + + @Override + public String getPwdByName(String name) { + return ctBuyerDao.getPwdByName(name); + } + + @Override + public CtBuyer getBuyerOccupyStatusLock(String buyerName) { + return ctBuyerDao.getBuyerOccupyStatusLock(buyerName); + } + + @Override + public Map getBuyerList(List buyerAccountList) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in("account", buyerAccountList); + + List ctBuyerList = list(queryWrapper); + if (ObjectUtil.isNotEmpty(ctBuyerList)) { + return ctBuyerList.stream().collect(Collectors.toMap(CtBuyer::getAccount, CtBuyer->CtBuyer)); + } + return null; + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/CtCardServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtCardServiceImpl.java new file mode 100644 index 0000000..e36521c --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtCardServiceImpl.java @@ -0,0 +1,33 @@ +package me.zhengjie.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.dao.CtCardDao; +import me.zhengjie.entity.CtCard; +import me.zhengjie.entity.CtCardInfo; +import me.zhengjie.service.CtCardService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 信用卡信息(CtCard)表服务实现类 + * + * @author rch + * @since 2022-07-07 + */ +@Service +public class CtCardServiceImpl extends ServiceImpl implements CtCardService { + + @Resource + private CtCardDao ctCardDao; + + @Override + public List getNumberList() { + return ctCardDao.getNumberList(); + } + + @Override + public List getCardInfoByNumber(List number){ return ctCardDao.getCardInfoByNumber(number);} +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/CtClickFarmingServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtClickFarmingServiceImpl.java new file mode 100644 index 0000000..ea01a9d --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtClickFarmingServiceImpl.java @@ -0,0 +1,62 @@ +package me.zhengjie.service.impl; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.dao.CtClickFarmingDao; +import me.zhengjie.entity.CtBuyerClickSuccess; +import me.zhengjie.entity.CtClickFarmYdParams; +import me.zhengjie.entity.CtClickFarming; +import me.zhengjie.service.CtClickFarmingService; +import me.zhengjie.service.vo.CtClickFarmEditDetailVO; +import me.zhengjie.service.vo.CtClickFarmingDetailVO; +import me.zhengjie.service.vo.CtClickFarmingVO; +import me.zhengjie.utils.PageUtils; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 刷单Excel信息(CtClickFarming)表服务实现类 + * + * @author rch + * @since 2022-08-16 + */ +@Service +public class CtClickFarmingServiceImpl extends ServiceImpl implements CtClickFarmingService { + + @Resource + private CtClickFarmingDao ctClickFarmingDao; + @Override + public PageUtils searchPageList(IPage page, Wrapper ew) { + ctClickFarmingDao.searchPageList(page, ew); + return new PageUtils(page.getTotal(), page.getRecords()); + } + + @Override + public CtClickFarming getByIdLock(Long id) { + return ctClickFarmingDao.getByIdLock(id); + } + + @Override + public CtClickFarmEditDetailVO getEditDetailById(Long id) { + return ctClickFarmingDao.getEditDetailById(id); + } + + @Override + public CtClickFarmingDetailVO getDetailById(Long id) { + return ctClickFarmingDao.getDetailById(id); + } + + @Override + public List ruleGetCtBuyer(String buyerAccount, String country, String shopName) { + return ctClickFarmingDao.ruleGetCtBuyer(buyerAccount, country, shopName); + } + + @Override + public CtClickFarmYdParams getCtClickFarmYdParams(Long id) { + return ctClickFarmingDao.getCtClickFarmYdParams(id); + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/CtClickOrderServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtClickOrderServiceImpl.java new file mode 100644 index 0000000..1b0f3e1 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtClickOrderServiceImpl.java @@ -0,0 +1,90 @@ +package me.zhengjie.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.dao.CtClickOrderDao; +import me.zhengjie.entity.CtClickFarming; +import me.zhengjie.entity.CtClickFarmingOrderInfo; +import me.zhengjie.entity.CtClickOrder; +import me.zhengjie.enums.ClickFarmingStatusEnum; +import me.zhengjie.service.CtClickFarmingService; +import me.zhengjie.service.CtClickOrderService; +import me.zhengjie.service.vo.CtClickOrderDetailVO; +import me.zhengjie.service.vo.CtClickOrderListVO; +import me.zhengjie.utils.PageUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 刷单-订单信息(CtClickOrder)表服务实现类 + * + * @author rch + * @since 2022-09-14 + */ +@Service +public class CtClickOrderServiceImpl extends ServiceImpl implements CtClickOrderService { + + @Resource + private CtClickOrderDao ctClickOrderDao; + @Resource + private CtClickFarmingService ctClickFarmingService; + + @Override + public List getOrderId(List importOrderIdList) { + List orderIdList = new ArrayList<>(); + QueryWrapper queryWrapper = new QueryWrapper(); + queryWrapper.in("order_id", importOrderIdList) + .select("order_id"); + List queryClickOrderIdList = list(queryWrapper); + if (ObjectUtil.isNotEmpty(queryClickOrderIdList)) { + orderIdList = queryClickOrderIdList.stream().map(q->q.getOrderId()).collect(Collectors.toList()); + } + return orderIdList; + } + + @Override + public PageUtils searchPageList(IPage page, Wrapper ew) { + ctClickOrderDao.searchPageList(page, ew); + return new PageUtils(page.getTotal(), page.getRecords()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean supplement(Long clickFarmingId, CtClickOrder ctClickOrder) { + Boolean saveBoolean = save(ctClickOrder); + if (!saveBoolean) { + return false; + } + Long ctOrderId = ctClickOrder.getId(); + CtClickFarming ctClickFarming = new CtClickFarming(); + ctClickFarming.setId(clickFarmingId); + ctClickFarming.setCtClickOrderId(ctOrderId); + ctClickFarming.setStatus(ClickFarmingStatusEnum.EXECUTION_SUCCESS.value()); + + return ctClickFarmingService.updateById(ctClickFarming); + } + + @Override + public CtClickFarmingOrderInfo getClickFarmOrderById(Long orderId) { + return ctClickOrderDao.getClickFarmOrderById(orderId); + } + + @Override + public CtClickOrder getByIdLock(Long id) { + return ctClickOrderDao.getByIdLock(id); + } + + @Override + public CtClickOrderDetailVO getClickOrderDetailById(Long id) { + return ctClickOrderDao.getClickOrderDetailById(id); + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/CtCompanyServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtCompanyServiceImpl.java new file mode 100644 index 0000000..e5948ac --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtCompanyServiceImpl.java @@ -0,0 +1,53 @@ +package me.zhengjie.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.dao.CtCompanyDao; +import me.zhengjie.entity.CtCompany; +import me.zhengjie.entity.CtCompanyInfo; +import me.zhengjie.entity.CtPlatform; +import me.zhengjie.service.CtCompanyService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 公司信息(CtCompany)表服务实现类 + * + * @author makejava + * @since 2022-06-23 10:37:44 + */ +@Service +public class CtCompanyServiceImpl extends ServiceImpl implements CtCompanyService { + + @Resource + private CtCompanyDao ctCompanyDao; + + @Override + public List getByNmae(List name) { + return ctCompanyDao.getByName(name); + } + + @Override + public List getCompanyList() { + return ctCompanyDao.getCompanyList(); + } + + @Override + public Map getNameList(List platNameList) { + Map ctCompanyMap = new HashMap<>(16); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in("name", platNameList).select("id", "name"); + List ctCompanyList = list(queryWrapper); + if (ObjectUtil.isNotEmpty(ctCompanyList)) { + ctCompanyMap = ctCompanyList.stream().collect(Collectors.toMap(CtCompany::getId, CtCompany::getName)); + } + return ctCompanyMap; + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/CtDhPayServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtDhPayServiceImpl.java new file mode 100644 index 0000000..bf25565 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtDhPayServiceImpl.java @@ -0,0 +1,100 @@ +package me.zhengjie.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.config.DhApiProperties; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.dao.CtDhPayDao; +import me.zhengjie.entity.CtDhPay; +import me.zhengjie.entity.CtDhPayExport; +import me.zhengjie.enums.DhPayStatusEnum; +import me.zhengjie.enums.ExcelStatusEnum; +import me.zhengjie.service.CtBuyerService; +import me.zhengjie.service.CtDhPayService; +import me.zhengjie.service.vo.CtBuyerListVO; +import me.zhengjie.service.vo.CtDhPayListVO; +import me.zhengjie.service.vo.PayOrderVO; +import me.zhengjie.utils.HttpClientUtil; +import me.zhengjie.utils.PageUtils; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 平台信息(CtDyPay)表服务实现类 + * + * @author rch + * @since 2022-07-28 + */ +@Service +public class CtDhPayServiceImpl extends ServiceImpl implements CtDhPayService { + + @Resource + private CtDhPayDao ctDhPayDao; + + @Resource + private CtBuyerService ctBuyerService; + + @Override + public PageUtils searchPageList(IPage page, Wrapper ew) { + ctDhPayDao.searchPageList(page, ew); + return new PageUtils(page.getTotal(), page.getRecords()); + } + + @Override + public void toPay() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("status", DhPayStatusEnum.TO_BE.value()); + List ctDhPayList = list(queryWrapper); + + // for 循环下单处理 + for (CtDhPay ctDhPay :ctDhPayList) { + payOrderApi(ctDhPay); + } + } + + @Override + public Boolean payOrderApi(CtDhPay ctDhPay) { + + // TODO 参数检验验证 + + String buyerName = ctDhPay.getBuyerName(); + String pwd = ctBuyerService.getPwdByName(buyerName); + if (ObjectUtil.isEmpty(pwd)) { + return false; + } + + Map params = new HashMap<>(16); + // 统一请求参数 + params.put("timestamp", System.currentTimeMillis()); + params.put("v", DhApiProperties.PAY_ORDER_V); + params.put("access_token", pwd); + params.put("method", DhApiProperties.PAY_ORDER_METHOD); + + // boby + params.put("orderNo", ctDhPay.getOrderId()); + + String responseStr = HttpClientUtil.doPostHttp(DhApiProperties.PAY_ORDER_URL, params); + PayOrderVO payOrderVO = JSONUtil.toBean(responseStr, PayOrderVO.class); + Boolean requestBoolean = false; + // 成功 修改订单状态 以及填充接口响应信息 + if (ObjectUtil.isNotEmpty(payOrderVO) && PublicConstant.RESPONSE_SUCCESS.equals(payOrderVO.getResult()) && PublicConstant.DH_REQUEST_SUCCESS_STATUS_CODE.equals(payOrderVO.getStatus().getCode())) { + requestBoolean = true; + } + + Integer status = requestBoolean ? DhPayStatusEnum.PAY_SUCCESS.value() : DhPayStatusEnum.PAY_FAIL.value(); + CtDhPay updateCtDhPay = new CtDhPay(); + updateCtDhPay.setId(ctDhPay.getId()); + updateCtDhPay.setResponse(JSONUtil.toJsonStr(payOrderVO)); + updateCtDhPay.setStatus(status); + return updateById(updateCtDhPay); + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/CtExcelImportInfoServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtExcelImportInfoServiceImpl.java new file mode 100644 index 0000000..0a86ff5 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtExcelImportInfoServiceImpl.java @@ -0,0 +1,174 @@ +package me.zhengjie.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.Snowflake; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.config.PropertiesConfig; +import me.zhengjie.config.SystemConfig; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.dao.CtExcelImportInfoDao; +import me.zhengjie.entity.*; +import me.zhengjie.enums.ExcelInfoRequestTypeEnum; +import me.zhengjie.enums.ExcelStatusEnum; +import me.zhengjie.service.CtBuyerService; +import me.zhengjie.service.CtCompanyService; +import me.zhengjie.service.CtExcelImportInfoService; +import me.zhengjie.service.CtExcelService; +import me.zhengjie.utils.excel.ExcelUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Excel导入信息(CtExcelImportInfo)表服务实现类 + * + * @author rch + * @since 2022-06-23 + */ +@Slf4j +@Service +public class CtExcelImportInfoServiceImpl extends ServiceImpl implements CtExcelImportInfoService { + + @Resource + private CtExcelService ctExcelService; + @Resource + private CtCompanyService ctCompanyService; + @Resource + private CtBuyerService ctBuyerService; + @Resource + private PropertiesConfig propertiesConfig; + @Resource + private Snowflake snowflake; + + @Override + public void importExcel() throws IOException { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(CtExcel::getStatus, ExcelStatusEnum.TOBE.value()); + + List ctExcelList = ctExcelService.list(queryWrapper); + // 导入存储数据库业务逻辑 + if (ObjectUtil.isNotEmpty(ctExcelList)) { + + // TODO -判断公司和token 是否匹配 不匹配则导入失败 + + // 符合条件的往下走 + String errorUrlPath = saveExcel(ctExcelList); + LambdaQueryWrapper updateStatusQW = new LambdaQueryWrapper<>(); + List ctExcelIdList = ctExcelList.stream().map(CtExcel::getId).collect(Collectors.toList()); + updateStatusQW.in(CtExcel::getId, ctExcelIdList); + + int status = ObjectUtil.isEmpty(errorUrlPath) ? ExcelStatusEnum.SUCCESS.value() : ExcelStatusEnum.FAILE.value(); + // 不符合条件的 直接失败 + CtExcel updateCtExcel = new CtExcel(); + updateCtExcel.setErrorPath(errorUrlPath); + updateCtExcel.setStatus(status); + ctExcelService.update(updateCtExcel, updateStatusQW); + } + } + + /** + * 导入业务逻辑 + * @param ctExcelList + * @return + */ + public String saveExcel(List ctExcelList) throws IOException { + + String returnDataStr = null; + List excelImportInfoList = new ArrayList<>(); + + for (CtExcel ctExcel:ctExcelList) { + String platImageUrl = SystemConfig.IMG_PATH; + String pathUrl = ctExcel.getPath(); + String excelPathUrl = platImageUrl + pathUrl; + + // 读取文件 + File file = new File(excelPathUrl); + try { + List excelImportInfoTempList = ExcelUtils.readFile(file, CtExcelImportInfo.class); + if (ObjectUtil.isNotEmpty(excelImportInfoTempList)) { + excelImportInfoList.addAll(excelImportInfoTempList); + } + } catch (Exception exception) { + System.out.println(exception.getMessage()); + } + } + + // 存储mysql + if (ObjectUtil.isNotEmpty(excelImportInfoList)) { + + + List addCtExcelImportInfoList = new ArrayList<>(); + List errorCtExcelExportInfoList = new ArrayList<>(); + + List companyIdList = excelImportInfoList.stream().map(CtExcelImportInfo::getCompanyId).collect(Collectors.toList()); + QueryWrapper queryWrapperCompany = new QueryWrapper<>(); + queryWrapperCompany.in("id", companyIdList); + List ctCompanyList = ctCompanyService.list(queryWrapperCompany); + + List buyerIdList = excelImportInfoList.stream().map(CtExcelImportInfo::getTokenEnum).collect(Collectors.toList()); + QueryWrapper queryWrapperBuyer = new QueryWrapper<>(); + queryWrapperBuyer.in("id", buyerIdList); + List ctBuyerList = ctBuyerService.list(queryWrapperBuyer); + + // 新增订单编号 + for (CtExcelImportInfo ctExcelImportInfo:excelImportInfoList) { + CtExcelExportInfo ctExcelExportInfo = new CtExcelExportInfo(); + BeanUtil.copyProperties(ctExcelImportInfo, ctExcelExportInfo); + // TODO 检验Excel 导入的文件是否符合要求 符合要求导入 不符合要求则直接Excel错误信息导出 + StringBuffer errorStrBuf = new StringBuffer(); + if (ObjectUtil.isEmpty(ctCompanyList) + || ctCompanyList.stream().filter(c->c.getId().equals(ctExcelImportInfo.getCompanyId())).count() <= 0) { + errorStrBuf.append("公司信息不存在!"); + errorStrBuf.append(";"); + } + + if (ObjectUtil.isEmpty(ctBuyerList) + || ctBuyerList.stream().filter(c->c.getId().equals(ctExcelImportInfo.getTokenEnum())).count() <= 0) { + errorStrBuf.append("买家信息不存在!"); + errorStrBuf.append(";"); + } + + if (ObjectUtil.isNotEmpty(errorStrBuf)) { + ctExcelExportInfo.setError(errorStrBuf.toString()); + errorCtExcelExportInfoList.add(ctExcelExportInfo); + } else { + CtBuyerContactInfo ctBuyerContactInfo = new CtBuyerContactInfo(); + CtBuyer ctBuyer = ctBuyerList.stream().filter(c->c.getId().equals(ctExcelImportInfo.getTokenEnum())).findFirst().get(); + // 取出收款地址信息 + BeanUtil.copyProperties(ctBuyer, ctBuyerContactInfo); + + ctExcelImportInfo.setOrderNo(snowflake.nextIdStr()); + ctExcelImportInfo.setContactInfo(JSONUtil.toJsonStr(ctBuyerContactInfo)); + addCtExcelImportInfoList.add(ctExcelImportInfo); + } + } + + // TODO 不符合条件的 Excel 导出 返回导出excel url url = errorExcelUrl; + String filePath = propertiesConfig.getUploadImgPath().get(PublicConstant.EXPORT_EXCEL_FILE_TYPE); + String fileName = "下单信息导入异常信息表-" + snowflake.nextIdStr(); + if (ObjectUtil.isNotEmpty(errorCtExcelExportInfoList)) { + ExcelUtils.exportFile(SystemConfig.IMG_PATH + filePath, fileName, errorCtExcelExportInfoList); + returnDataStr = SystemConfig.FILE_VISIT_ADDR + filePath + fileName + ".xlsx"; + // returnDataStr = "http://localhost:8008/file" + filePath + fileName + ".xlsx"; + } + // 如何条件的导入 + if (ObjectUtil.isNotEmpty(addCtExcelImportInfoList)) { + saveBatch(addCtExcelImportInfoList); + } + } + return returnDataStr; + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/CtExcelServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtExcelServiceImpl.java new file mode 100644 index 0000000..6cfbb08 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtExcelServiceImpl.java @@ -0,0 +1,19 @@ +package me.zhengjie.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.dao.CtExcelDao; +import me.zhengjie.entity.CtExcel; +import me.zhengjie.service.CtExcelService; +import org.springframework.stereotype.Service; + +/** + * Excel 导入信息(CtExcel)表服务实现类 + * + * @author makejava + * @since 2022-06-23 10:37:44 + */ +@Service +public class CtExcelServiceImpl extends ServiceImpl implements CtExcelService { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/CtOrderServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtOrderServiceImpl.java new file mode 100644 index 0000000..9fe1f5b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtOrderServiceImpl.java @@ -0,0 +1,196 @@ +package me.zhengjie.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.config.DhApiProperties; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.dao.CtOrderDao; +import me.zhengjie.entity.*; +import me.zhengjie.enums.ExcelStatusEnum; +import me.zhengjie.service.*; +import me.zhengjie.service.vo.*; +import me.zhengjie.utils.HttpClientUtil; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * (CtOrder)表服务实现类 + * + * @author rch + * @since 2022-07-01 + */ +@Service +public class CtOrderServiceImpl extends ServiceImpl implements CtOrderService { + + @Resource + private CtExcelImportInfoService ctExcelImportInfoService; + @Resource + private CtResponseOrderService ctResponseOrderService; + @Resource + private CtResponseOrderAddressService ctResponseOrderAddressService; + @Resource + private CtResponseOrderProductService ctResponseOrderProductService; + @Resource + private CtBuyerService ctBuyerService; + + @Override + public void excelToOrder() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("status", ExcelStatusEnum.TOBE.value()); + List ctExcelImportInfoList = ctExcelImportInfoService.list(queryWrapper); + + for (CtExcelImportInfo ctExcelImportInfo:ctExcelImportInfoList) { + buyOrderApi(ctExcelImportInfo); + } + } + + @Transactional(rollbackFor = Exception.class) + public Boolean buyOrderApi(CtExcelImportInfo ctExcelImportInfo) { + + // TODO 请求参数解析 检验 -先不做 + + // 获取买家access_token + Long buyerId = ctExcelImportInfo.getTokenEnum(); + CtBuyer ctBuyer = ctBuyerService.getById(buyerId); + + Map params = new HashMap<>(); + // 统一请求参数 + params.put("timestamp", System.currentTimeMillis()); + params.put("v", DhApiProperties.BUY_ORDER_V); + params.put("access_token", ctBuyer.getPwd()); + params.put("method", DhApiProperties.BUY_ORDER_METHOD); + + // boby + params.put("fromDetailInfo", ctExcelImportInfo.getFromDetailInfo()); + String carList = ctExcelImportInfo.getCartList(); + String contacInfo = ctExcelImportInfo.getContactInfo(); + params.put("cartList", carList); + params.put("contactInfo", contacInfo); + + + String responseStr = HttpClientUtil.doPostHttp(DhApiProperties.BUY_ORDER_URL, params); + + // 请求响应转对象 + BuyOrderVO buyOrderVO = JSONUtil.toBean(responseStr, BuyOrderVO.class); + System.out.println("buyOrderVO: " + buyOrderVO.toString()); + + Boolean saveOrderBathResult = false; + // 业务逻辑处理 数据处理 + if (ObjectUtil.isNotEmpty(buyOrderVO) && PublicConstant.DH_REQUEST_SUCCESS_STATUS_CODE.equals(buyOrderVO.getStatus().getCode())) { + // 接口响应码以及响应信息 + OrderResponStatusVO orderResponStatus = buyOrderVO.getStatus(); + // 请求接口响应内容 + List OrderResponseList = buyOrderVO.getOrderList(); + + List orderList = new ArrayList<>(); + Long companyId = ctExcelImportInfo.getCompanyId(); + + for (OrderResponseVO orderResponseVO:OrderResponseList) { + CtOrder ctOrder = new CtOrder(); + ctOrder.setCompanyId(companyId); + ctOrder.setBuyerId(buyerId); + ctOrder.setBuyAccessToken(ctBuyer.getPwd()); + ctOrder.setExcelInfoId(ctExcelImportInfo.getId()); + ctOrder.setCtOrderNo(ctExcelImportInfo.getOrderNo()); + ctOrder.setOrderResponseStatus(JSONUtil.toJsonStr(orderResponStatus)); + + // ct_response_order + CtResponseOrder ctResponseOrder = new CtResponseOrder(); + BuyOrderResponseOrderVO buyOrderResponseOrderVO = orderResponseVO.getOrderInfo(); + BeanUtil.copyProperties(buyOrderResponseOrderVO, ctResponseOrder); + System.out.println("======ctResponseOrder:" + ctResponseOrder); + // order 特殊处理 对应响应的id + Long responseOrderId = buyOrderResponseOrderVO.getId(); + ctResponseOrder.setOrderId(responseOrderId); + ctResponseOrderService.save(ctResponseOrder); + Long saveResponseOrderId = ctResponseOrder.getId(); + ctOrder.setResponseOrderId(saveResponseOrderId); + ctOrder.setOrderNo(responseOrderId); + + // ct_response_address + CtResponseOrderAddress ctResponseOrderAddress = new CtResponseOrderAddress(); + BuyOrderResponseAddressVO buyOrderResponseAddress = orderResponseVO.getOrderContactInfo(); + BeanUtil.copyProperties(buyOrderResponseAddress, ctResponseOrderAddress); + System.out.println("======ctResponseOrderAddress:" + ctResponseOrderAddress); + ctResponseOrderAddressService.save(ctResponseOrderAddress); + Long responseOrderAddressId = ctResponseOrderAddress.getId(); + ctOrder.setResponseOrderAddressId(responseOrderAddressId); + + // ct_response_product + // TODO -这里商品响应是一个集合 这里目前看都是单个,先不考虑 + CtResponseOrderProduct ctResponseOrderProduct = new CtResponseOrderProduct(); + List buyOrderResponseProductList = orderResponseVO.getCartList(); + BeanUtil.copyProperties(buyOrderResponseProductList.get(0), ctResponseOrderProduct); + System.out.println("======ctResponseOrderProduct:" + ctResponseOrderProduct); + ctResponseOrderProductService.save(ctResponseOrderProduct); + Long responseproductId = ctResponseOrderProduct.getId(); + ctOrder.setResponseProductId(responseproductId); + + orderList.add(ctOrder); + } + + saveOrderBathResult = saveBatch(orderList); + } + + // 修改Excel状态 + Integer status = saveOrderBathResult ? ExcelStatusEnum.SUCCESS.value() : ExcelStatusEnum.FAILE.value(); + CtExcelImportInfo updateCtExcelImportInfo = new CtExcelImportInfo(); + updateCtExcelImportInfo.setId(ctExcelImportInfo.getId()); + updateCtExcelImportInfo.setStatus(status); + ctExcelImportInfoService.updateById(updateCtExcelImportInfo); + + return true; + } + + @Override + public void toPay() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("status", ExcelStatusEnum.TOBE.value()); + List ctOrderList = list(queryWrapper); + + for (CtOrder ctOrder:ctOrderList) { + payOrderApi(ctOrder); + } + } + + @Override + public Boolean payOrderApi(CtOrder ctOrder) { + + // TODO 参数检验验证 + + Map params = new HashMap<>(); + // 统一请求参数 + params.put("timestamp", System.currentTimeMillis()); + params.put("v", DhApiProperties.PAY_ORDER_V); + params.put("access_token", ctOrder.getBuyAccessToken()); + params.put("method", DhApiProperties.PAY_ORDER_METHOD); + + // boby + params.put("orderNo", ctOrder.getOrderNo()); + + String responseStr = HttpClientUtil.doPostHttp(DhApiProperties.PAY_ORDER_URL, params); + PayOrderVO payOrderVO = JSONUtil.toBean(responseStr, PayOrderVO.class); + Boolean requestBoolean = false; + // 成功 修改订单状态 以及填充接口响应信息 + if (ObjectUtil.isNotEmpty(payOrderVO) && PublicConstant.RESPONSE_SUCCESS.equals(payOrderVO.getResult()) && PublicConstant.DH_REQUEST_SUCCESS_STATUS_CODE.equals(payOrderVO.getStatus().getCode())) { + requestBoolean = true; + } + + Integer status = requestBoolean ? ExcelStatusEnum.SUCCESS.value() : ExcelStatusEnum.FAILE.value(); + CtOrder updateCtOrder = new CtOrder(); + updateCtOrder.setId(ctOrder.getId()); + updateCtOrder.setPayResponseStatus(JSONUtil.toJsonStr(payOrderVO)); + updateCtOrder.setStatus(status); + return updateById(updateCtOrder); + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/CtPlatformServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtPlatformServiceImpl.java new file mode 100644 index 0000000..b399b7b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtPlatformServiceImpl.java @@ -0,0 +1,37 @@ +package me.zhengjie.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.dao.CtPlatformDao; +import me.zhengjie.entity.CtPlatform; +import me.zhengjie.service.CtPlatformService; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 平台信息(CtPlatform)表服务实现类 + * + * @author makejava + * @since 2022-06-23 10:37:44 + */ +@Service +public class CtPlatformServiceImpl extends ServiceImpl implements CtPlatformService { + + @Override + public Map getNameList(List platNameList) { + Map ctPlatformMap = new HashMap<>(16); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in("name", platNameList).select("id", "name"); + List ctPlatformList = list(queryWrapper); + if (ObjectUtil.isNotEmpty(ctPlatformList)) { + ctPlatformMap = ctPlatformList.stream().collect(Collectors.toMap(CtPlatform::getId, CtPlatform::getName)); + } + return ctPlatformMap; + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/CtRebotServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtRebotServiceImpl.java new file mode 100644 index 0000000..93120c8 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtRebotServiceImpl.java @@ -0,0 +1,127 @@ +package me.zhengjie.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.Snowflake; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.config.PropertiesConfig; +import me.zhengjie.config.SystemConfig; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.dao.CtRebotDao; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.CtRebot; +import me.zhengjie.entity.CtRebotExport; +import me.zhengjie.entity.CtRebotImport; +import me.zhengjie.service.CtRebotService; +import me.zhengjie.service.vo.CtRebotListVO; +import me.zhengjie.utils.PageUtils; +import me.zhengjie.utils.excel.ExcelUtils; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.List; + +/** + * 影刀设备-机器人信息(CtRebot)表服务实现类 + * + * @author rch + * @since 2022-07-23 + */ +@Service +public class CtRebotServiceImpl extends ServiceImpl implements CtRebotService { + + @Resource + private CtRebotDao ctRebotDao; + @Resource + private PropertiesConfig propertiesConfig; + @Resource + private Snowflake snowflake; + + @Override + public CtRebot getByAccountNameLock(String accountName) { + return ctRebotDao.getByAccountNameLock(accountName); + } + + @Override + public PageUtils searchPageList(IPage page, Wrapper ew) { + ctRebotDao.searchRebotList(page,ew); + return new PageUtils<>(page.getTotal(),page.getRecords()); + } + + @Override + public Dto importRebot(MultipartFile file, HttpServletResponse response)throws Exception { + List ctRebotImportList = ExcelUtils.readMultipartFile(file,CtRebotImport.class); + if(ObjectUtil.isEmpty(ctRebotImportList)){ + return Dto.returnResult(false); + } + + List addCtRebotList = new ArrayList<>(); + List ctRebotExportList = new ArrayList<>(); + List rebotNameList = getAccountNameList(); + List rebotUuidList = getClientUuidList(); + + for(CtRebotImport ctRebotImport : ctRebotImportList){ + CtRebotExport ctRebotExport = new CtRebotExport(); + BeanUtil.copyProperties(ctRebotImport,ctRebotExport); + + StringBuffer errorBuffer = new StringBuffer(); + String rowTips = ctRebotImport.getRowTips(); + if(ObjectUtil.isNotEmpty(rowTips)){ + errorBuffer.append(rowTips); + errorBuffer.append(";"); + } + if(rebotNameList.contains(ctRebotImport.getAccountName())){ + errorBuffer.append("已存在该名称对应的机器人信息"); + errorBuffer.append(";"); + } + if(rebotUuidList.contains(ctRebotImport.getRobotClientUuid())){ + errorBuffer.append("已存在该Uuid对应的机器人信息"); + errorBuffer.append(";"); + } + if(ObjectUtil.isNotEmpty(errorBuffer)){ + ctRebotExport.setError(errorBuffer.toString()); + ctRebotExportList.add(ctRebotExport); + }else{ + CtRebot ctRebot = new CtRebot(); + BeanUtil.copyProperties(ctRebotImport,ctRebot); + addCtRebotList.add(ctRebot); + } + } + + String returnDataStr = null; + String filePath = propertiesConfig.getUploadImgPath().get(PublicConstant.EXPORT_EXCEL_FILE_TYPE); + String fileName = "机器人导入异常信息表-" + snowflake.nextIdStr(); + if(ObjectUtil.isNotEmpty(ctRebotExportList)){ + ExcelUtils.exportFile(SystemConfig.IMG_PATH + filePath, fileName, ctRebotExportList); + returnDataStr = SystemConfig.FILE_VISIT_ADDR + filePath + fileName + ".xlsx"; + //returnDataStr = "http://localhost:8008/file" + filePath + fileName + ".xlsx"; + } + + if(ObjectUtil.isNotEmpty(addCtRebotList)){ + saveBatch(addCtRebotList); + } + + return Dto.returnResult(ObjectUtil.isEmpty(returnDataStr) ? true : returnDataStr); + } + + @Override + public List getAccountNameList() { + return ctRebotDao.getAccountNameList(); + } + + @Override + public List getClientUuidList() { + return ctRebotDao.getClientUuidList(); + } + + @Override + public Boolean updateNewStatusByOldStatus(Long id, Integer newStatus, Integer oldStatus) { + return ctRebotDao.updateNewStatusByOldStatus(id, newStatus, oldStatus); + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/CtResponseOrderAddressServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtResponseOrderAddressServiceImpl.java new file mode 100644 index 0000000..96ee9e6 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtResponseOrderAddressServiceImpl.java @@ -0,0 +1,19 @@ +package me.zhengjie.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.dao.CtResponseOrderAddressDao; +import me.zhengjie.entity.CtResponseOrderAddress; +import me.zhengjie.service.CtResponseOrderAddressService; +import org.springframework.stereotype.Service; + +/** + * 下注成功订单响应收货地址信息(CtResponseOrderAddress)表服务实现类 + * + * @author rch + * @since 2022-07-01 + */ +@Service +public class CtResponseOrderAddressServiceImpl extends ServiceImpl implements CtResponseOrderAddressService { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/CtResponseOrderProductServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtResponseOrderProductServiceImpl.java new file mode 100644 index 0000000..9045753 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtResponseOrderProductServiceImpl.java @@ -0,0 +1,19 @@ +package me.zhengjie.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.dao.CtResponseOrderProductDao; +import me.zhengjie.entity.CtResponseOrderProduct; +import me.zhengjie.service.CtResponseOrderProductService; +import org.springframework.stereotype.Service; + +/** + * 下单订单响应产品信息(CtResponseOrderProduct)表服务实现类 + * + * @author rch + * @since 2022-07-01 + */ +@Service +public class CtResponseOrderProductServiceImpl extends ServiceImpl implements CtResponseOrderProductService { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/CtResponseOrderServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtResponseOrderServiceImpl.java new file mode 100644 index 0000000..1aab77d --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtResponseOrderServiceImpl.java @@ -0,0 +1,19 @@ +package me.zhengjie.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.dao.CtResponseOrderDao; +import me.zhengjie.entity.CtResponseOrder; +import me.zhengjie.service.CtResponseOrderService; +import org.springframework.stereotype.Service; + +/** + * 下单成功响应订单商品信息(CtResponseOrder)表服务实现类 + * + * @author rch + * @since 2022-07-01 + */ +@Service +public class CtResponseOrderServiceImpl extends ServiceImpl implements CtResponseOrderService { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/CtVpnServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtVpnServiceImpl.java new file mode 100644 index 0000000..db2730a --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/CtVpnServiceImpl.java @@ -0,0 +1,31 @@ +package me.zhengjie.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.dao.CtVpnDao; +import me.zhengjie.entity.CtVpn; +import me.zhengjie.entity.CtVpnInfo; +import me.zhengjie.service.CtVpnService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * VPN信息表(CtVpn)表服务实现类 + * + * @author rch + * @since 2022-07-07 + */ +@Service +public class CtVpnServiceImpl extends ServiceImpl implements CtVpnService { + + @Resource + private CtVpnDao ctVpnDao; + + @Override + public List getIpList() { return ctVpnDao.getIpList(); } + + @Override + public List getVpnInfoByIp(List ipAddress){ return ctVpnDao.getVpnInfoByIp(ipAddress);} +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/DhAddCarOrderServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/DhAddCarOrderServiceImpl.java new file mode 100644 index 0000000..3d9143b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/DhAddCarOrderServiceImpl.java @@ -0,0 +1,98 @@ +package me.zhengjie.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.dao.DhAddCarOrderDao; +import me.zhengjie.dao.DhCarGoodsDao; +import me.zhengjie.entity.DhAddCarOrder; +import me.zhengjie.entity.DhCarGoods; +import me.zhengjie.enums.ParamsTypeEnum; +import me.zhengjie.service.DhAddCarOrderService; +import me.zhengjie.service.vo.dhaddcar.DhAddCarVO; +import me.zhengjie.service.vo.dhcargood.DhCarGoodKeyVO; +import me.zhengjie.service.vo.dhcargood.DhCarGoodLinkVO; +import me.zhengjie.service.vo.dhcarorder.DhAddCarOrderListVO; +import me.zhengjie.service.vo.dhcarorder.DhCarOrderParamsVO; +import me.zhengjie.utils.PageUtils; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 敦煌-加购物车-订单(DhAddCarOrder)表服务实现类 + * + * @author rch + * @since 2022-11-17 09:12:00 + */ +@Service +public class DhAddCarOrderServiceImpl extends ServiceImpl implements DhAddCarOrderService { + + @Resource + private DhAddCarOrderDao dhAddCarOrderDao; + + @Resource + private DhCarGoodsDao dhCarGoodsDao; + + @Override + public DhAddCarOrder getByIdLock(Long id) { + return dhAddCarOrderDao.getByIdLock(id); + } + + @Override + public PageUtils searchPageList(IPage page, Wrapper ew) { + dhAddCarOrderDao.searchPageList(page, ew); + return new PageUtils(page.getTotal(), page.getRecords()); + } + + @Override + public DhCarOrderParamsVO getYdParams(Long id) { + DhCarOrderParamsVO dhCarOrderParamsVO = dhAddCarOrderDao.getYdParams(id); + if (ObjectUtil.isEmpty(dhCarOrderParamsVO)) { + return dhCarOrderParamsVO; + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("params_type", dhCarOrderParamsVO.getParamsType()); + queryWrapper.in("id", Arrays.asList(dhCarOrderParamsVO.getCarGoodIds().split(","))); + List DhCarGoods = dhCarGoodsDao.selectList(queryWrapper); + if (ObjectUtil.isEmpty(DhCarGoods)) { + return dhCarOrderParamsVO; + } + + List carGoodKeyList = new ArrayList<>(); + List carGoodLinkList = new ArrayList<>(); + for (DhCarGoods dhCarGoods:DhCarGoods) { + if (ParamsTypeEnum.KEY_WORD.eqValue(dhCarOrderParamsVO.getParamsType())) { + + DhCarGoodKeyVO dhCarGoodKeyVO = new DhCarGoodKeyVO(); + BeanUtil.copyProperties(dhCarGoods, dhCarGoodKeyVO); + carGoodKeyList.add(dhCarGoodKeyVO); + } else if (ParamsTypeEnum.LINK.eqValue(dhCarOrderParamsVO.getParamsType())) { + + DhCarGoodLinkVO dhCarGoodLinkVO = new DhCarGoodLinkVO(); + BeanUtil.copyProperties(dhCarGoods, dhCarGoodLinkVO); + carGoodLinkList.add(dhCarGoodLinkVO); + } else { + continue; + } + } + + if (ObjectUtil.isNotEmpty(carGoodKeyList)) { + dhCarOrderParamsVO.setCarGoodKeys(carGoodKeyList); + } + + if (ObjectUtil.isNotEmpty(carGoodLinkList)) { + dhCarOrderParamsVO.setCarGoodLinks(carGoodLinkList); + } + return dhCarOrderParamsVO; + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/DhAddCarServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/DhAddCarServiceImpl.java new file mode 100644 index 0000000..9b45a16 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/DhAddCarServiceImpl.java @@ -0,0 +1,108 @@ +package me.zhengjie.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.dao.DhAddCarDao; +import me.zhengjie.entity.DhAddCar; +import me.zhengjie.entity.DhCarGoods; +import me.zhengjie.enums.ParamsTypeEnum; +import me.zhengjie.service.DhAddCarService; +import me.zhengjie.service.DhCarGoodsService; +import me.zhengjie.service.vo.dhaddcar.DhAddCarListVO; +import me.zhengjie.service.vo.dhaddcar.DhAddCarVO; +import me.zhengjie.service.vo.dhaddcar.DhAddCarYdParamsVO; +import me.zhengjie.service.vo.dhcargood.DhCarGoodKeyVO; +import me.zhengjie.service.vo.dhcargood.DhCarGoodLinkVO; +import me.zhengjie.utils.PageUtils; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 敦煌加入购物车(DhAddCar)表服务实现类 + * + * @author rch + * @since 2022-11-17 09:11:56 + */ +@Service +public class DhAddCarServiceImpl extends ServiceImpl implements DhAddCarService { + + @Resource + private DhAddCarDao dhAddCarDao; + @Resource + private DhCarGoodsService dhCarGoodsService; + + @Override + public PageUtils searchPageList(IPage page, Wrapper ew) { + dhAddCarDao.searchPageList(page, ew); + return new PageUtils(page.getTotal(), page.getRecords()); + } + + @Override + public DhAddCarVO getDetailById(Long id) { + DhAddCarVO dhAddCarVO = dhAddCarDao.getDetailById(id); + if (ObjectUtil.isEmpty(dhAddCarVO)) { + return dhAddCarVO; + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("params_type", dhAddCarVO.getParamsType()); + queryWrapper.in("id", Arrays.asList(dhAddCarVO.getCarGoodIds().split(","))); + List DhCarGoods = dhCarGoodsService.list(queryWrapper); + if (ObjectUtil.isEmpty(DhCarGoods)) { + return dhAddCarVO; + } + + List carGoodKeyList = new ArrayList<>(); + List carGoodLinkList = new ArrayList<>(); + for (DhCarGoods dhCarGoods:DhCarGoods) { + if (ParamsTypeEnum.KEY_WORD.eqValue(dhAddCarVO.getParamsType())) { + + DhCarGoodKeyVO dhCarGoodKeyVO = new DhCarGoodKeyVO(); + BeanUtil.copyProperties(dhCarGoods, dhCarGoodKeyVO); + carGoodKeyList.add(dhCarGoodKeyVO); + } else if (ParamsTypeEnum.LINK.eqValue(dhAddCarVO.getParamsType())) { + + DhCarGoodLinkVO dhCarGoodLinkVO = new DhCarGoodLinkVO(); + BeanUtil.copyProperties(dhCarGoods, dhCarGoodLinkVO); + carGoodLinkList.add(dhCarGoodLinkVO); + } else { + continue; + } + } + + if (ObjectUtil.isNotEmpty(carGoodKeyList)) { + dhAddCarVO.setCarGoodKeys(carGoodKeyList); + } + + if (ObjectUtil.isNotEmpty(carGoodLinkList)) { + dhAddCarVO.setCarGoodLinks(carGoodLinkList); + } + return dhAddCarVO; + } + + @Override + public DhAddCar getByIdLock(Long id) { + return dhAddCarDao.getByIdLock(id); + } + + @Override + public DhAddCarYdParamsVO getAddCarYdParams(Long id) { + DhAddCarYdParamsVO dhAddCarYdParamsVO = new DhAddCarYdParamsVO(); + DhAddCarVO dhAddCarVO = getDetailById(id); + if (ObjectUtil.isEmpty(dhAddCarVO)) { + return dhAddCarYdParamsVO; + } + + BeanUtil.copyProperties(dhAddCarVO, dhAddCarYdParamsVO); + return dhAddCarYdParamsVO; + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/DhCarGoodsServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/DhCarGoodsServiceImpl.java new file mode 100644 index 0000000..f18256a --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/DhCarGoodsServiceImpl.java @@ -0,0 +1,19 @@ +package me.zhengjie.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.dao.DhCarGoodsDao; +import me.zhengjie.entity.DhCarGoods; +import me.zhengjie.service.DhCarGoodsService; +import org.springframework.stereotype.Service; + +/** + * 敦煌-加入购物车商品信息(DhCarGoods)表服务实现类 + * + * @author makejava + * @since 2022-11-17 09:12:04 + */ +@Service +public class DhCarGoodsServiceImpl extends ServiceImpl implements DhCarGoodsService { + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/FileUploadServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/FileUploadServiceImpl.java new file mode 100644 index 0000000..37d22fa --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/FileUploadServiceImpl.java @@ -0,0 +1,130 @@ +package me.zhengjie.service.impl; + + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Snowflake; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.config.PropertiesConfig; +import me.zhengjie.config.SystemConfig; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.service.FileUploadService; +import org.springframework.stereotype.Service; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static me.zhengjie.error.ErrorCodeEnum.UPLOAD_IMG_FORMAT_ERROR; +/** + *

+ * 图片上传服务 + *

+ * + * @Author xx + * @Date 2021/7/26 + **/ +@Slf4j +@Service +public class FileUploadServiceImpl implements FileUploadService { + + @Resource + private Snowflake snowflake; + @Resource + private PropertiesConfig config; + + @Override + public List uploadify(HttpServletRequest request, HttpServletResponse response) throws IOException { + response.setCharacterEncoding("utf-8"); + response.setContentType("application/json;charset=utf-8"); + response.setHeader("Cache-Control", "no-cache"); + Integer type = Convert.toInt(request.getParameter("type")); + + MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; + Map fileMap = multipartRequest.getFileMap(); + // 如果有传文件路径,则为替换文件, + String fileUrl = request.getParameter("fileUrl"); + + List returnStr = new ArrayList(); + if (ObjectUtil.isNotEmpty(fileUrl)) { + for (String key : fileMap.keySet()) { + MultipartFile multipartFile = fileMap.get(key); + isTrue(multipartFile,type); + // 文件覆盖 + File uploadFile = new File(SystemConfig.IMG_PATH + "/" + fileUrl); + + FileCopyUtils.copy(multipartFile.getBytes(), uploadFile); + returnStr.add(MapUtil.of("path", fileUrl)); + break; + } + }else { + for (String key : fileMap.keySet()) { + MultipartFile mf = fileMap.get(key); + isTrue(mf,type); + // 文件保存路径 + String filePath = config.getUploadImgPath().get(type); + filePath = filePath + LocalDate.now().toString().replaceAll("-","")+"/"; + + File file = new File(SystemConfig.IMG_PATH + filePath); + if (!file.exists()) { + file.mkdirs(); + } + // 文件名 + String fileEnd = mf.getOriginalFilename(); + fileEnd = fileEnd.substring(fileEnd.lastIndexOf(".")); + String newfileName = snowflake.nextIdStr() + fileEnd; + // 文件保存到本地 + File uploadFile = new File(file.getAbsolutePath() + "/" + newfileName); + FileCopyUtils.copy(mf.getBytes(), uploadFile); + String path = filePath + newfileName; + returnStr.add(MapUtil.of("path", path)); + } + } + + return returnStr; + } + + + /** + * 上传文件验证,如果验证不通过将抛出异常 + * + * @author: zeng + */ + private void isTrue(MultipartFile mf,Integer type) { + int maxFileSize = SystemConfig.MAX_FILE_SIZE; + if (type.equals(8)){ + maxFileSize = SystemConfig.VIDEO_MAX_FILE_SIZE; + } + if (mf.getSize()>(maxFileSize*1024*1024)){ + throw new BadRequestException(2005, "文件大小不超过于" + maxFileSize + "M"); + } + String fileEnd = mf.getOriginalFilename(); + fileEnd = fileEnd.substring(fileEnd.lastIndexOf(".")); + // 文件格式验证 + if (!imgFormat(fileEnd.substring(1))){ + UPLOAD_IMG_FORMAT_ERROR.setDesc(fileEnd+" 上传图片格式错误"); + throw new BadRequestException(UPLOAD_IMG_FORMAT_ERROR); + } + } + + + private boolean imgFormat(String fileEnd) { + for (String s : config.getSustainImgFormat()) { + if (s.equalsIgnoreCase(fileEnd)) { + return true; + } + } + return false; + } + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/LoginIpServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/LoginIpServiceImpl.java new file mode 100644 index 0000000..bf9256f --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/LoginIpServiceImpl.java @@ -0,0 +1,121 @@ +package me.zhengjie.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import me.zhengjie.dao.LoginIpDao; +import me.zhengjie.entity.LoginIp; +import me.zhengjie.service.LoginIpService; +import me.zhengjie.service.vo.LoginIpVO; +import me.zhengjie.utils.DateUtil; +import me.zhengjie.utils.LoginIpUtil; +import me.zhengjie.utils.PageUtils; +import me.zhengjie.utils.RedisUtils; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + * (LoginIp)表服务实现类 + * + * @author zeng + * @since 2022-03-21 14:07:01 + */ +@Service +@RequiredArgsConstructor +public class LoginIpServiceImpl extends ServiceImpl implements LoginIpService { + + final RedisUtils redisUtils; + + @Override + public PageUtils getList(IPage iPage) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.orderByDesc(LoginIp::getId); + page(iPage, lqw); + ArrayList arrayList = new ArrayList(); + for (LoginIp record : iPage.getRecords()) { + LoginIpVO loginIpVO = new LoginIpVO(record); + arrayList.add(loginIpVO); + } + return new PageUtils(iPage.getTotal(), arrayList); + } + + @Override + public boolean addIp(LoginIp ip) { + if (save(ip)) { + redisUtils.lPush(LoginIpService.LOGIN_IP_LIST, ip); + return true; + } + return false; + } + + @Override + public List getAll() { + List list = redisUtils.lGet(LoginIpService.LOGIN_IP_LIST, 0, -1); + if (ObjectUtil.isEmpty(list)) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.ge(LoginIp::getVaildTime, DateUtil.getCurrentTime()).or(q->q.eq(LoginIp::getVaildTime,"")); + return list(lqw); + } + return list; + } + + @Override + public boolean updateIp(LoginIp ip) { + if (updateById(ip)) { + List list = getAll(); + for (LoginIp loginIp : list) { + if (loginIp.getId().equals(ip.getId())) { + redisUtils.lRemove(LoginIpService.LOGIN_IP_LIST, 1, loginIp); + break; + } + } + redisUtils.lPush(LoginIpService.LOGIN_IP_LIST, ip); + return true; + } + return false; + } + + @Override + public boolean deleteIp(Integer id) { + if (removeById(id)) { + List list = getAll(); + for (LoginIp loginIp : list) { + if (loginIp.getId().equals(id)) { + redisUtils.lRemove(LoginIpService.LOGIN_IP_LIST, 1, loginIp); + } + } + } + return false; + } + + @Override + public boolean whiteListFlag(String ip) { + List ipList = getAll(); + if (ObjectUtil.isNotEmpty(ipList)) { + boolean flag = false; + for (LoginIp loginIp : ipList) { + if (ObjectUtil.isNotEmpty(loginIp.getVaildTime())) { + LocalDateTime localDateTime = DateUtil.parseLocalDateTimeFormatyMdHms(loginIp.getVaildTime()); + if (localDateTime.isBefore(LocalDateTime.now())) { + // 失效 + redisUtils.lRemove(LoginIpService.LOGIN_IP_LIST, 1, loginIp); + continue; + } + } + if (LoginIpUtil.ipExistsInRange(ip, loginIp.getIpStart(), loginIp.getIpEnd())) { + return true; + } + } + return false; + } + return true; + } + + +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/SettingSiteServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/SettingSiteServiceImpl.java new file mode 100644 index 0000000..56538f3 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/SettingSiteServiceImpl.java @@ -0,0 +1,75 @@ +package me.zhengjie.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.dao.SettingSiteDao; +import me.zhengjie.entity.CtSettingSite; +import me.zhengjie.service.SettingSiteService; +import me.zhengjie.utils.RedisUtils; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +import static me.zhengjie.constant.PublicConstant.CACHE_OVER_TIME; +import static me.zhengjie.constant.PublicConstant.SETTING_SITE_PREFIX; + +/** + * 站点配置(CtSettingSite)表服务实现类 + * + * @author makejava + * @since 2021-11-17 17:02:11 + */ +@Service +@Slf4j +public class SettingSiteServiceImpl extends ServiceImpl implements SettingSiteService { + @Resource + private RedisUtils redisUtils; + @Resource + private SettingSiteDao settingSiteDao; + + @Override + public String getValue(String key) { + String prefix = String.format(SETTING_SITE_PREFIX, key); + Object value = redisUtils.get(prefix); + + if (ObjectUtil.isNotEmpty(value)) { + return value.toString(); + } + String valueByKey = settingSiteDao.getValueByKey(key); + redisUtils.set(prefix, valueByKey, CACHE_OVER_TIME); + return valueByKey; + } + + @Override + public boolean saveOrUpdateByKey(String key, String value) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper(); + lqw.eq(CtSettingSite::getSettingKey, key); + boolean boo; + if (count(lqw) > 0) { + LambdaUpdateWrapper luw = new LambdaUpdateWrapper(); + luw.eq(CtSettingSite::getSettingKey, key); + luw.set(CtSettingSite::getSettingValue, value); + boo = update(luw); + }else { + CtSettingSite site = new CtSettingSite(); + site.setContent(""); + site.setSettingKey(key); + site.setSettingValue(value); + boo = save(site); + } + if (boo) { + String prefix = String.format(SETTING_SITE_PREFIX, key); + redisUtils.set(prefix, value, CACHE_OVER_TIME); + } + return boo; + } + + @Override + public Boolean getGooleAuthSwitch() { + return "1".equals(settingSiteDao.getValueByKey("googleAuth")) ? true : false; + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/SysQuartzJobServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/SysQuartzJobServiceImpl.java new file mode 100644 index 0000000..1975f7c --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/SysQuartzJobServiceImpl.java @@ -0,0 +1,63 @@ +//package me.zhengjie.service.impl; +// +//import cn.hutool.core.bean.BeanUtil; +//import com.baomidou.mybatisplus.core.conditions.Wrapper; +//import com.baomidou.mybatisplus.core.metadata.IPage; +//import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +//import lombok.RequiredArgsConstructor; +//import me.zhengjie.dao.SysQuartzJobDao; +//import me.zhengjie.entity.SysQuartzJob; +//import me.zhengjie.enums.TaskTypeEnum; +//import me.zhengjie.service.SysQuartzJobService; +//import me.zhengjie.service.vo.SysQuartzJobListVO; +//import me.zhengjie.utils.PageUtils; +//import me.zhengjie.utils.RedisUtils; +//import org.apache.logging.log4j.core.layout.SyslogLayout; +//import org.springframework.stereotype.Service; +// +//import javax.annotation.Resource; +// +///** +// * 定时任务(SysQuartzJob)表服务实现类 +// * +// * @author rch +// * @since 2022-07-20 +// */ +//@Service +//@RequiredArgsConstructor +//public class SysQuartzJobServiceImpl extends ServiceImpl implements SysQuartzJobService { +// +// @Resource +// private SysQuartzJobService sysQuartzJobService; +// @Resource +// private SysQuartzJobDao sysQuartzJobDao; +// +// private final QuartzJobRepository quartzJobRepository; +// private final QuartzLogRepository quartzLogRepository; +// private final QuartzManage quartzManage; +// private final RedisUtils redisUtils; +// +// @Override +// public PageUtils searchPageList(IPage page, Wrapper wrapper) { +// sysQuartzJobDao.searchPageList(page,wrapper); +// return new PageUtils(page.getTotal(),page.getRecords()); +// } +// +// @Override +// public boolean modifyJobStatus(Long jobId) { +// SysQuartzJob sysQuartzJobIsExist = sysQuartzJobService.getById(jobId); +// if(sysQuartzJobIsExist == null){ +// return false; +// }else{ +// SysQuartzJob sysQuartzJob = new SysQuartzJob(); +// BeanUtil.copyProperties(sysQuartzJobIsExist,sysQuartzJob); +// if(sysQuartzJob.getIsPause() == 0){ +// sysQuartzJob.setIsPause(1); +// }else{ +// sysQuartzJob.setIsPause(0); +// } +// return sysQuartzJobService.updateById(sysQuartzJob); +// } +// } +//} +// diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/SysQuartzLogServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/SysQuartzLogServiceImpl.java new file mode 100644 index 0000000..aac7886 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/SysQuartzLogServiceImpl.java @@ -0,0 +1,35 @@ +package me.zhengjie.service.impl; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import me.zhengjie.dao.SysQuartzJobDao; +import me.zhengjie.dao.SysQuartzLogDao; +import me.zhengjie.entity.SysQuartzJob; +import me.zhengjie.entity.SysQuartzLog; +import me.zhengjie.service.SysQuartzLogService; +import me.zhengjie.service.vo.SysQuartzLogListVO; +import me.zhengjie.utils.PageUtils; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * 定时任务(SysQuartzJob)表服务实现类 + * + * @author rch + * @since 2022-07-20 + */ +@Service +public class SysQuartzLogServiceImpl extends ServiceImpl implements SysQuartzLogService { + + @Resource + private SysQuartzLogDao sysQuartzLogDao; + + @Override + public PageUtils searchPageList(IPage page, Wrapper wrapper) { + sysQuartzLogDao.searchPageList(page, wrapper); + return new PageUtils(page.getTotal(), page.getRecords()); + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/impl/YdQuartzServiceImpl.java b/wjcy-common/src/main/java/me/zhengjie/service/impl/YdQuartzServiceImpl.java new file mode 100644 index 0000000..d0b54b9 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/impl/YdQuartzServiceImpl.java @@ -0,0 +1,464 @@ +package me.zhengjie.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.config.BeanFactory; +import me.zhengjie.constant.Constants; +import me.zhengjie.entity.*; +import me.zhengjie.entity.quartz.*; +import me.zhengjie.enums.*; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.service.*; +import me.zhengjie.service.redission.LockCallBack; +import me.zhengjie.utils.HttpClientUtil; +import me.zhengjie.utils.RedissonUtil; +import org.redisson.api.RLock; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * 影刀定时任务Service 实现类 + * + * @author rch + * @create 2022-08-01 + */ +@Service +@Slf4j +public class YdQuartzServiceImpl implements YdQuartzService { + + @Resource + private CtRebotService ctRebotService; + @Resource + private CtApplyService ctApplyService; + @Resource + private RedissonUtil redissonUtil; + @Resource + private CtClickFarmingService ctClickFarmingService; + @Resource + private CtBuyerService ctBuyerService; + @Resource + private CtClickOrderService ctClickOrderService; + @Resource + private DhAddCarOrderService dhAddCarOrderService; + @Resource + private DhAddCarService dhAddCarService; + @Resource + private CtBrowseService ctBrowseService; + + @Override + public Object executeOnLock(String lockKey, long time, long timeout, LockCallBack callBack) throws Exception { + RLock lock = redissonUtil.getRLock(lockKey); + String currentTime = me.zhengjie.utils.DateUtil.getCurrentTime(); + try { + log.info(currentTime + " 获取锁============= {}",lockKey); + if (lock.tryLock(time, timeout, TimeUnit.SECONDS)) { + System.out.println("run111 ====== lock success "); + return callBack.execute(true); + } else { + System.out.println("run111 ====== lock fail "); + throw new BadRequestException(" lock fail "); + } + } catch (Exception e) { + throw e; + } finally { + lock.unlock(); + log.info(currentTime+" 释放锁============= {}",lockKey); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public String exec(String str) throws Exception { + Boss boss = JSONUtil.toBean(str, Boss.class); + // 1.根据设备id获取设备信息 for update + CtRebot ctRebot = ctRebotService.getByAccountNameLock(boss.getAccountName()); + System.out.println(JSONUtil.toJsonStr(ctRebot)); + if (ObjectUtil.isEmpty(ctRebot) || !YesOrNoEnum.NO.eqValue(ctRebot.getStatus())) { + // 有问题 不执行 + log.info("机器人设备信息不存在,或者机器人状态不可用!"); + throw new BadRequestException("机器人设备信息不存在,或者机器人状态不可用!"); + } + + // TODO 这里需要根据应用获取 appKey appSecret信息 + CtApply ctApply = ctApplyService.getById(boss.getApplyId()); + if (ObjectUtil.isEmpty(ctApply) + || ObjectUtil.isEmpty(ctApply.getRobotUuid()) + || ObjectUtil.isEmpty(ctApply.getAccessKeyId()) + || ObjectUtil.isEmpty(ctApply.getAccessKeySecret())) { + log.info("影刀应用信息不存在,或者影刀应用信息异常!"); + throw new BadRequestException("影刀应用信息不存在,或者影刀应用信息异常!"); + } + + // 判断买家是否占用 + List paramList = boss.getParams().stream().filter(n->n.getName().equals("account")).collect(Collectors.toList()); + if (ObjectUtil.isEmpty(paramList)) { + throw new BadRequestException("买家信息不存在!"); + } + String buyerName = paramList.get(0).getValue(); + CtBuyer ctBuyer = ctBuyerService.getBuyerOccupyStatusLock(buyerName); + if (ObjectUtil.isEmpty(ctBuyer) || BuyerOccupyStatusEnum.OCCUPIED.value().equals(ctBuyer.getOccupyStatus())) { + throw new BadRequestException("买家信息不存在,或者已占用状态!"); + } + + boss.setRobotUuid(ctApply.getRobotUuid()); + // token + Map params = new HashMap<>(16); + params.put("accessKeyId", ctApply.getAccessKeyId()); + params.put("accessKeySecret", ctApply.getAccessKeySecret()); + SecreInfo secreInfo = JSONUtil.toBean(HttpClientUtil.getHttp(Constants.GET_SECRET, params), SecreInfo.class); + if (!secreInfo.getSuccess()) { + log.info("=========鉴权异常=========="); + throw new BadRequestException("请求影刀鉴权异常!"); + } + String token = secreInfo.getData().getAccessToken(); + System.out.println("====token===="); + Map headers = new HashMap<>(16); + headers.put("Accept", "application/json"); + headers.put("Content-Type", "application/json;charset=utf-8"); + headers.put("authorization", "Bearer " + token); + + // 判断是否在线 + RebotStatu rebotStatu = new RebotStatu(ctRebot.getRobotClientUuid(), ctRebot.getAccountName()); + String returnStr = HttpClientUtil.postJson(Constants.REBOT_STATU, headers, JSONUtil.toJsonStr(rebotStatu), "utf-8"); + RebotStatuReturn rebotStatuReturn = JSONUtil.toBean(returnStr, RebotStatuReturn.class); + // 状态 connected:已连接 idle:空闲 running:运行中 allocated:已分配 abnormal:异常 offline:离线 + if (RobotStatusEnum.OFFLINE.value().equals(rebotStatuReturn.getData().getStatus())) { + log.info("=======设备不在线====="); + throw new BadRequestException("设备不在线!"); + } else if (RobotStatusEnum.RUNNING.value().equals(rebotStatuReturn.getData().getStatus())) { + log.info("=======设备运行中====="); + throw new BadRequestException("设备运行中!"); + } else if (RobotStatusEnum.ALLOCATED.value().equals(rebotStatuReturn.getData().getStatus())) { + log.info("=======设备已分配====="); + throw new BadRequestException("设备已分配!"); + } else if (RobotStatusEnum.ABNORMAL.value().equals(rebotStatuReturn.getData().getStatus())) { + log.info("=======设备异常====="); + throw new BadRequestException("设备异常!"); + } + // 启动Job + String returnJobStr = null; + CtRebot updateCtRebot = new CtRebot(); + updateCtRebot.setId(ctRebot.getId()); + updateCtRebot.setStatus(YesOrNoEnum.YES.value()); + CtRebotService ctRebotService = BeanFactory.getBean(CtRebotService.class); + Boolean resultBoolean = ctRebotService.updateById(updateCtRebot); + if (resultBoolean) { + // 修改买家信息占用状态 + ctBuyer.setOccupyStatus(BuyerOccupyStatusEnum.OCCUPIED.value()); + if (ctBuyerService.updateById(ctBuyer)) { + returnJobStr = HttpClientUtil.postJson(Constants.STAT_JOB_URL, headers, JSONUtil.toJsonStr(boss), "utf-8"); + StartYdReturnInfo startYdReturnInfo = JSONUtil.toBean(returnJobStr, StartYdReturnInfo.class); + if (startYdReturnInfo.getSuccess()) { + log.info("run111 执行成功,返回结果为: {}" + returnJobStr); + } else { + throw new BadRequestException(startYdReturnInfo.getMsg()); + } + } else { + log.info("run111 执行成功。 但是修改设备状态失败----- 此处该预警"); + throw new BadRequestException("修改设备状态失败!"); + } + } else { + log.info("run111 执行成功。 但是修改设备状态失败----- 此处该预警"); + throw new BadRequestException("修改设备状态失败!"); + } + return returnJobStr; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean clickFarmExec(String str) throws Exception { + System.out.println("================================ClickFarmTask=========================4"); + // 只有真正发起了执行 状态才修改为执行中 回调后修改成功 或者失败 + // TODO 这里根据响应结果 修改平台状态 类型,根据boss里面的 执行中 别的任务如果想再执行这个刷单信息, 不允许执行。 执行前加锁查询, 带执行状态才可以往下走 + // 修改状态为 执行中。 + + Boss boss = JSONUtil.toBean(str, Boss.class); + List paramList = boss.getParams(); + // 获取ID + String id = paramList.stream().filter(p->p.getName().equals("id")).collect(Collectors.toList()).get(0).getValue(); + CtClickFarming ctClickFarming = ctClickFarmingService.getByIdLock(Long.valueOf(id)); + if (ClickFarmingStatusEnum.IN_EXECUTION.value().equals(ctClickFarming.getStatus())) { + throw new BadRequestException("该定时任务对应的刷单信息已经执行中状态,请检查后重试!"); + } + + if (ClickFarmingStatusEnum.EXECUTION_SUCCESS.value().equals(ctClickFarming.getStatus())) { + throw new BadRequestException("该定时任务对应的刷单信息已执行成功,请检查后重试!"); + } + + String returnStartJobStr = exec(str); + if (ObjectUtil.isEmpty(returnStartJobStr)) { + throw new BadRequestException("调用影刀启动任务失败! response:" + returnStartJobStr); + } + + YdStartReturn ydStartReturn = JSONUtil.toBean(returnStartJobStr, YdStartReturn.class); + if (!ydStartReturn.getSuccess()) { + throw new BadRequestException("调用影刀启动任务失败! response:" + returnStartJobStr); + } + + // 修改状态 带执行 - 》 执行中 + CtClickFarming updateCtClickFarming = new CtClickFarming(); + updateCtClickFarming.setId(ctClickFarming.getId()); + updateCtClickFarming.setStatus(ClickFarmingStatusEnum.IN_EXECUTION.value()); + return ctClickFarmingService.updateById(updateCtClickFarming); + } + + + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean addCarExec(String str) throws Exception { + System.out.println("================================ClickFarmTask=========================4"); + // 只有真正发起了执行 状态才修改为执行中 回调后修改成功 或者失败 + // TODO 这里根据响应结果 修改平台状态 类型,根据boss里面的 执行中 别的任务如果想再执行这个刷单信息, 不允许执行。 执行前加锁查询, 带执行状态才可以往下走 + // 修改状态为 执行中。 + + Boss boss = JSONUtil.toBean(str, Boss.class); + List paramList = boss.getParams(); + // 获取ID + String id = paramList.stream().filter(p->p.getName().equals("id")).collect(Collectors.toList()).get(0).getValue(); + DhAddCar dhAddCar = dhAddCarService.getByIdLock(Long.valueOf(id)); + if (!DhAddCarStatusEnum.TOBE_EXECUTION.value().equals(dhAddCar.getStatus()) && !DhAddCarStatusEnum.ADD_CARD_FAILE.value().equals(dhAddCar.getStatus())) { + throw new BadRequestException("该定时任务对应的敦煌加购必须带执行或执行失败,请检查后重试!"); + } + + if (DhAddCarStatusEnum.Add_CARD_SUCCESS.value().equals(dhAddCar.getStatus())) { + throw new BadRequestException("该定时任务对应的敦煌加购已执行成功,请检查后重试!"); + } + + String returnStartJobStr = exec(str); + if (ObjectUtil.isEmpty(returnStartJobStr)) { + throw new BadRequestException("调用影刀启动任务失败! response:" + returnStartJobStr); + } + + YdStartReturn ydStartReturn = JSONUtil.toBean(returnStartJobStr, YdStartReturn.class); + if (!ydStartReturn.getSuccess()) { + throw new BadRequestException("调用影刀启动任务失败! response:" + returnStartJobStr); + } + + // 修改状态 带执行 - 》 执行中 + DhAddCar updateDhAddCar = new DhAddCar(); + updateDhAddCar.setId(dhAddCar.getId()); + updateDhAddCar.setStatus(ClickFarmingStatusEnum.IN_EXECUTION.value()); + return dhAddCarService.updateById(updateDhAddCar); + } + + + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean catchOrderExec(String str) throws Exception { + System.out.println("================================catchOrderExec=========================4"); + // 只有真正发起了执行 状态才修改为执行中 回调后修改成功 或者失败 + // TODO 这里根据响应结果 修改平台状态 类型,根据boss里面的 执行中 别的任务如果想再执行这个刷单信息, 不允许执行。 执行前加锁查询, 带执行状态才可以往下走 + // 修改状态为 执行中。 + + Boss boss = JSONUtil.toBean(str, Boss.class); + List paramList = boss.getParams(); + // 获取ID + String id = paramList.stream().filter(p->p.getName().equals("id")).collect(Collectors.toList()).get(0).getValue(); + DhAddCar dhAddCar = dhAddCarService.getByIdLock(Long.valueOf(id)); + if (!DhAddCarStatusEnum.TO_BE_CATCH_ORDER.value().equals(dhAddCar.getStatus()) && !DhAddCarStatusEnum.CATCH_ORDER_FAILE.value().equals(dhAddCar.getStatus())) { + throw new BadRequestException("该定时任务对应的敦煌加购抓单必须是待抓单或者抓单失败状态!"); + } + + String returnStartJobStr = exec(str); + if (ObjectUtil.isEmpty(returnStartJobStr)) { + throw new BadRequestException("调用影刀启动任务失败! response:" + returnStartJobStr); + } + + YdStartReturn ydStartReturn = JSONUtil.toBean(returnStartJobStr, YdStartReturn.class); + if (!ydStartReturn.getSuccess()) { + throw new BadRequestException("调用影刀启动任务失败! response:" + returnStartJobStr); + } + + // 修改状态 带抓单/抓单失败 - 》 抓单中 + DhAddCar updateDhAddCar = new DhAddCar(); + updateDhAddCar.setId(dhAddCar.getId()); + updateDhAddCar.setStatus(DhAddCarStatusEnum.CATCH_ORDER_ING.value()); + return dhAddCarService.updateById(updateDhAddCar); + } + + + // TODO 这里查询任务结果然后返回, 在回调哪里 调用这个方法,然后解析参数, 入参 出参 和执行结果状态等。 + @Override + @Transactional(rollbackFor = Exception.class) + public JobQueryByUuidReturn queryJobUuid(String uuid, String accessKeyId, String accessKeySecret) { + // token + Map params = new HashMap<>(16); + params.put("accessKeyId", accessKeyId); + params.put("accessKeySecret", accessKeySecret); + String response = HttpClientUtil.getHttp(Constants.GET_SECRET, params); + log.error("鉴权请求结果:" +response); + SecreInfo secreInfo = JSONUtil.toBean(response, SecreInfo.class); + if (ObjectUtil.isEmpty(secreInfo) || !secreInfo.getSuccess()) { + log.info("=========鉴权异常=========="); + throw new BadRequestException("请求影刀鉴权异常!"); + } + String token = secreInfo.getData().getAccessToken(); + Map headers = new HashMap<>(16); + headers.put("Accept", "application/json"); + headers.put("Content-Type", "application/json;charset=utf-8"); + headers.put("authorization", "Bearer " + token); + + // 判断是否在线 + JobQueryByUuid jobQueryByUuid = new JobQueryByUuid(); + jobQueryByUuid.setJobUuid(uuid); + String returnStr = HttpClientUtil.postJson(Constants.QUERY_JOB_URL, headers, JSONUtil.toJsonStr(jobQueryByUuid), "utf-8"); + log.info("====returnStr====" + returnStr); + JobQueryByUuidReturn jobQueryByUuidReturn = JSONUtil.toBean(returnStr, JobQueryByUuidReturn.class); + + return jobQueryByUuidReturn; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean clickFarmSuppleMentExec(String str) throws Exception { + System.out.println("================================ClickFarmSuppleMentTask=========================4"); + // 只有真正发起了执行 状态才修改为执行中 回调后修改成功 或者失败 + // TODO 这里根据响应结果 修改平台状态 类型,根据boss里面的 执行中 别的任务如果想再执行这个刷单信息, 不允许执行。 执行前加锁查询, 带执行状态才可以往下走 + // 修改状态为 执行中。 + + Boss boss = JSONUtil.toBean(str, Boss.class); + List paramList = boss.getParams(); + // 获取ID + String id = paramList.stream().filter(p->p.getName().equals("id")).collect(Collectors.toList()).get(0).getValue(); + CtClickFarming ctClickFarming = ctClickFarmingService.getByIdLock(Long.valueOf(id)); + if (!ClickFarmingStatusEnum.AWAITING_PAYMENT.value().equals(ctClickFarming.getStatus())) { + throw new BadRequestException("仅待支付状态才允许补录,请检查后重试!"); + } + + String returnStartJobStr = exec(str); + if (ObjectUtil.isEmpty(returnStartJobStr)) { + throw new BadRequestException("调用影刀启动任务失败! response:" + returnStartJobStr); + } + + YdStartReturn ydStartReturn = JSONUtil.toBean(returnStartJobStr, YdStartReturn.class); + if (!ydStartReturn.getSuccess()) { + throw new BadRequestException("调用影刀启动任务失败! response:" + returnStartJobStr); + } + + // 修改状态 带执行 - 》 执行中 + CtClickFarming updateCtClickFarming = new CtClickFarming(); + updateCtClickFarming.setId(ctClickFarming.getId()); + updateCtClickFarming.setStatus(ClickFarmingStatusEnum.IN_EXECUTION.value()); + return ctClickFarmingService.updateById(updateCtClickFarming); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Object dhWellReceivedExec(String str) throws Exception { + System.out.println("================================WellReceivedExec=========================4"); + // 只有真正发起了执行 状态才修改为执行中 回调后修改成功 或者失败 + // 修改状态为 执行中。 + + Boss boss = JSONUtil.toBean(str, Boss.class); + List paramList = boss.getParams(); + // 获取ID + String id = paramList.stream().filter(p->p.getName().equals("id")).collect(Collectors.toList()).get(0).getValue(); + DhAddCarOrder dhAddCarOrder = dhAddCarOrderService.getByIdLock(Long.valueOf(id)); + if (ClickOrderStatusEnum.IN_EXECUTION.value().equals(dhAddCarOrder.getStatus())) { + throw new BadRequestException("该定时任务对应的敦煌加购好评信息已经执行中状态,请检查后重试!"); + } + + if (ClickFarmingStatusEnum.EXECUTION_SUCCESS.value().equals(dhAddCarOrder.getStatus())) { + throw new BadRequestException("该定时任务对应的敦煌加购好评信息已执行成功,请检查后重试!"); + } + + String returnStartJobStr = exec(str); + if (ObjectUtil.isEmpty(returnStartJobStr)) { + throw new BadRequestException("调用影刀启动任务失败! response:" + returnStartJobStr); + } + + YdStartReturn ydStartReturn = JSONUtil.toBean(returnStartJobStr, YdStartReturn.class); + if (!ydStartReturn.getSuccess()) { + throw new BadRequestException("调用影刀启动任务失败! response:" + returnStartJobStr); + } + + // 修改状态 带执行 - 》 执行中 + DhAddCarOrder updateDhAddCarOrder = new DhAddCarOrder(); + updateDhAddCarOrder.setId(dhAddCarOrder.getId()); + updateDhAddCarOrder.setStatus(ClickOrderStatusEnum.IN_EXECUTION.value()); + return dhAddCarOrderService.updateById(updateDhAddCarOrder); + } + + + @Override + @Transactional(rollbackFor = Exception.class) + public Object wellReceivedExec(String str) throws Exception { + System.out.println("================================WellReceivedExec=========================4"); + // 只有真正发起了执行 状态才修改为执行中 回调后修改成功 或者失败 + // 修改状态为 执行中。 + + Boss boss = JSONUtil.toBean(str, Boss.class); + List paramList = boss.getParams(); + // 获取ID + String id = paramList.stream().filter(p->p.getName().equals("id")).collect(Collectors.toList()).get(0).getValue(); + CtClickOrder ctClickOrder = ctClickOrderService.getByIdLock(Long.valueOf(id)); + if (ClickOrderStatusEnum.IN_EXECUTION.value().equals(ctClickOrder.getStatus())) { + throw new BadRequestException("该定时任务对应的敦煌加购好评信息已经执行中状态,请检查后重试!"); + } + + if (ClickFarmingStatusEnum.EXECUTION_SUCCESS.value().equals(ctClickOrder.getStatus())) { + throw new BadRequestException("该定时任务对应的敦煌加购好评信息已执行成功,请检查后重试!"); + } + + String returnStartJobStr = exec(str); + if (ObjectUtil.isEmpty(returnStartJobStr)) { + throw new BadRequestException("调用影刀启动任务失败! response:" + returnStartJobStr); + } + + YdStartReturn ydStartReturn = JSONUtil.toBean(returnStartJobStr, YdStartReturn.class); + if (!ydStartReturn.getSuccess()) { + throw new BadRequestException("调用影刀启动任务失败! response:" + returnStartJobStr); + } + + // 修改状态 带执行 - 》 执行中 + CtClickOrder updateCtClickOrder = new CtClickOrder(); + updateCtClickOrder.setId(ctClickOrder.getId()); + updateCtClickOrder.setStatus(ClickOrderStatusEnum.IN_EXECUTION.value()); + return ctClickOrderService.updateById(updateCtClickOrder); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Object browseTaskExec(String str) throws Exception { + System.out.println("================================browseTaskExec=========================4"); + // 只有真正发起了执行 状态才修改为执行中 回调后修改成功 或者失败 + // 修改状态为 执行中。 + + Boss boss = JSONUtil.toBean(str, Boss.class); + List paramList = boss.getParams(); + // 获取ID + String id = paramList.stream().filter(p->p.getName().equals("id")).collect(Collectors.toList()).get(0).getValue(); + CtBrowse ctBrowse = ctBrowseService.getByIdLock(Long.valueOf(id)); + if (ClickOrderStatusEnum.IN_EXECUTION.value().equals(ctBrowse.getStatus())) { + throw new BadRequestException("该定时任务对应的订单信息已经执行中状态,请检查后重试!"); + } + + if (ClickFarmingStatusEnum.EXECUTION_SUCCESS.value().equals(ctBrowse.getStatus())) { + throw new BadRequestException("该定时任务对应的订单信息已执行成功,请检查后重试!"); + } + + String returnStartJobStr = exec(str); + if (ObjectUtil.isEmpty(returnStartJobStr)) { + throw new BadRequestException("调用影刀启动任务失败! response:" + returnStartJobStr); + } + + YdStartReturn ydStartReturn = JSONUtil.toBean(returnStartJobStr, YdStartReturn.class); + if (!ydStartReturn.getSuccess()) { + throw new BadRequestException("调用影刀启动任务失败! response:" + returnStartJobStr); + } + + // 修改状态 带执行 - 》 执行中 + CtBrowse updateCtBrowse = new CtBrowse(); + updateCtBrowse.setId(ctBrowse.getId()); + updateCtBrowse.setStatus(ClickOrderStatusEnum.IN_EXECUTION.value()); + return ctBrowseService.updateById(updateCtBrowse); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/redission/LockCallBack.java b/wjcy-common/src/main/java/me/zhengjie/service/redission/LockCallBack.java new file mode 100644 index 0000000..8d8b5ff --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/redission/LockCallBack.java @@ -0,0 +1,8 @@ +package me.zhengjie.service.redission; + +@FunctionalInterface +public interface LockCallBack { + + Object execute(T t); + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/AdminGoogleAuthInfoVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/AdminGoogleAuthInfoVO.java new file mode 100644 index 0000000..4e5973e --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/AdminGoogleAuthInfoVO.java @@ -0,0 +1,31 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + *

+ * Admin 秘钥信息 + *

+ * + * @author: rch + * @since: 2020-08-26 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class AdminGoogleAuthInfoVO { + + /** Google 总开关 */ + private Boolean gogoleAuthSwitch; + + /** 用户信息 */ + private String userName; + + /** 二维码url 信息 */ + private String qrBarCodeUrl; + + /** 明文秘钥 */ + private String secret; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/BuyOrderResponseAddressVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/BuyOrderResponseAddressVO.java new file mode 100644 index 0000000..2364b02 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/BuyOrderResponseAddressVO.java @@ -0,0 +1,39 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 下注成功订单响应收货地址信息(CtResponseOrderAddress)表实体类 + * + * @author rch + * @since 2022-06-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class BuyOrderResponseAddressVO { + + /** 地址1 */ + private String addressline1; + /** 国家 */ + private String country; + /** 州 */ + private String state; + /** 电话 */ + private String tel; + /** lastname */ + private String lastname; + /** 税号 */ + private String vatNumber; + /** 城市 */ + private String city; + /** 地址2 */ + private String addressline2; + /** firstname */ + private String firstname; + /** 邮政编码 */ + private String postalcode; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/BuyOrderResponseOrderVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/BuyOrderResponseOrderVO.java new file mode 100644 index 0000000..be0997d --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/BuyOrderResponseOrderVO.java @@ -0,0 +1,54 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * 下单成功响应订单商品信息(CtResponseOrder)表实体类 + * + * @author rch + * @since 2022-06-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class BuyOrderResponseOrderVO { + + private Long id; + /** 运费 */ + private Double shipCost; + /** 产品总价 */ + private Double totalPriceOfProduct; + /** 备货期 */ + private Double leadingTime; + /** 订单总价 */ + private Double orderTotal; + /** 卖家Id */ + private String supplierId; + /** 卖家店铺coupon */ + private Double couponOfSeller; + /** 运输方式 */ + private String shipType; + /** 订单优惠 */ + private Double orderSave; + /** 税费手续费 */ + private Double taxCharge; + /** 买家Id */ + private String buyerId; + /** 税费 */ + private Double tax; + /** 促销折扣 */ + private Double promoDiscount; + /** 订单号--这个要特殊处理这个是对应响应的id字段 */ + private Long orderId; + /** DHcoupon */ + private Double couponDiscount; + /** 下单站点 */ + private String siteId; + /** 创建时间 */ + private Date createTime; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/BuyOrderResponseProductVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/BuyOrderResponseProductVO.java new file mode 100644 index 0000000..5f603a5 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/BuyOrderResponseProductVO.java @@ -0,0 +1,81 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * 下单订单响应产品信息(CtResponseOrderProduct)表实体类 + * + * @author rch + * @since 2022-06-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class BuyOrderResponseProductVO { + + /** 秒杀类型 */ + private String flashDeals; + /** 卖家设置价格 */ + private Double prodPriceOrg; + /** 产品skuId */ + private String skuId; + /** 购买数量 */ + private Integer cateDispId; + /** 商品总金额 */ + private Double amount; + /** 发布类目id */ + private String catePubId; + /** 促销折扣 */ + private Double promDis; + /** 产品单位名称 */ + private String measureName; + /** 短描 */ + private String shortDescription; + /** 卖家承诺运达天数 */ + private Integer promiseDays; + /** 备货国家 */ + private String stockin; + /** 产品图片(小图) */ + private String thumbnailImage; + /** 是否为样品 */ + private String isSample; + /** 最终运费 */ + private Double shipCost; + /** 卖家Id */ + private String supplierId; + /** 跨店满减金额 */ + private BigDecimal crossReduceAmount; + /** 产品itemcode */ + private Integer itemcode; + /** buyer选择的运输方式 */ + private String shipType; + /** 销售价格 */ + private Double originPrice; + /** 产品长描地址 */ + private String htmlUrl; + /** 产品图片(大图) */ + private String imageUrl; + /** 最终价格 */ + private Double price; + /** 产品URL */ + private String productUrl; + /** 备注 */ + private String remark; + /** lots */ + private Integer lots; + /** 产品名称 */ + private String productName; + /** 产品Id */ + private String productId; + /** 产品skumd5 */ + private String skuMd5; + /** 创建时间 */ + private Date createTime; + /** 产品单位Id */ + private String measureId; +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/BuyOrderVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/BuyOrderVO.java new file mode 100644 index 0000000..37dd881 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/BuyOrderVO.java @@ -0,0 +1,24 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 订单下单API响应对象 + * + * @author rch + * @create 2022-06-27 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class BuyOrderVO { + + /** 接口响应状态 响应码 响应内容等信息*/ + private OrderResponStatusVO status; + /** 接口响应订单信息 */ + private List orderList; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtApplyInfoVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtApplyInfoVO.java new file mode 100644 index 0000000..e1c57a1 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtApplyInfoVO.java @@ -0,0 +1,19 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 应用信息(ct_apply) VO + * @Author zhw + * @Date 2022-08-01 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtApplyInfoVO { + + private Long id; + private String name; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtApplyListVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtApplyListVO.java new file mode 100644 index 0000000..04270b8 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtApplyListVO.java @@ -0,0 +1,68 @@ +package me.zhengjie.service.vo; + + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 应用信息表(CtApply)表实体类 分页查询VO + * @author zhw + * @Data 2022-07-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("应用信息表") +public class CtApplyListVO { + + @ApiModelProperty(value = "id") + private Long id; + + @ApiModelProperty(value = "平台Id") + private Long platformId; + + @ApiModelProperty(value = "创建时间") + private String createdAt; + + @ApiModelProperty(value = "修改时间") + private String updatedAt; + + /** 操作人账号 */ + @ApiModelProperty(value = "操作人账号") + private String gmName; + + /** 应用名称 */ + @ApiModelProperty(value = "应用名称") + private String name; + + /** 任务名称 */ + @ApiModelProperty(value = "任务名称") + private String taskName; + + /** 方法名称 */ + @ApiModelProperty(value = "方法名称") + private String methodName; + + /** accessKeyID */ + @ApiModelProperty(value = "accessKeyID") + private String accessKeyId; + + /** accessKeySecret */ + @ApiModelProperty(value = "accessKeySecret") + private String accessKeySecret; + + /** 应用id */ + @ApiModelProperty(value = "应用id") + private String robotUuid; + + /** 备注 */ + @ApiModelProperty(value = "备注") + private String remark; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBrowseDetailVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBrowseDetailVO.java new file mode 100644 index 0000000..0a4b4ff --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBrowseDetailVO.java @@ -0,0 +1,73 @@ +package me.zhengjie.service.vo; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * 收藏浏览信息表(CtCard)表实体类 详情Detail + * + * @author rch + * @since 2022-07-09 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("收藏浏览详情") +public class CtBrowseDetailVO { + + @ApiModelProperty(value = "id") + private Long id; + + @ApiModelProperty(value = "创建时间") + private String createdAt; + + @ApiModelProperty(value = "修改时间") + private String updatedAt; + + /** 操作人账号*/ + @ApiModelProperty(value = "操作人账号") + private String gmName; + + /** 买家ID */ + @ApiModelProperty(value = "买家ID") + private Long buyerId; + + /** 国家 */ + @ApiModelProperty(value = "国家") + private String country; + + /** 账号 */ + @ApiModelProperty(value = "账号") + private String account; + + /** 密码 */ + @ApiModelProperty(value = "密码") + private String pwd; + + /** vpn分享链接 */ + @ApiModelProperty(value = "vpn分享链接") + private String vpnShare; + + /** 收藏链接 */ + @ApiModelProperty(value = "收藏链接") + private String linkUrl; + + /** 状态描述 */ + @ApiModelProperty(value = "状态描述") + private String paymentResults; + + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 */ + @ApiModelProperty(value = "状态 1.待执行 2.执行中 3.执行成功 4.执行失败") + private Integer status; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBrowseListVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBrowseListVO.java new file mode 100644 index 0000000..02d75fa --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBrowseListVO.java @@ -0,0 +1,63 @@ +package me.zhengjie.service.vo; + +import com.baomidou.mybatisplus.extension.activerecord.Model; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * 浏览收藏(CtBrowse)表实体类 VO + * + * @author rch + * @since 2022-11-04 09:45:31 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("浏览收藏VO") +public class CtBrowseListVO extends Model { + /** 主键ID */ + @ApiModelProperty(value = "主键ID") + private Long id; + + /** 买家ID */ + @ApiModelProperty(value = "买家ID") + private Long buyerId; + + /** 国家 */ + @ApiModelProperty(value = "国家") + private String country; + + /** 账号 */ + @ApiModelProperty(value = "账号") + private String account; + + /** 收藏链接 */ + @ApiModelProperty(value = "收藏链接") + private String linkUrl; + + /** 创建时间 */ + @ApiModelProperty(value = "创建时间") + private Date createdAt; + + /** 修改时间 */ + @ApiModelProperty(value = "修改时间") + private Date updatedAt; + + /** 状态描述 */ + @ApiModelProperty(value = "状态描述") + private String paymentResults; + + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 */ + @ApiModelProperty(value = "状态 1.待执行 2.执行中 3.执行成功 4.执行失败") + private Integer status; + + /** 操作人账号 */ + @ApiModelProperty(value = "操作人账号") + private String gmName; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBuyerClickFarmVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBuyerClickFarmVO.java new file mode 100644 index 0000000..21ff831 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBuyerClickFarmVO.java @@ -0,0 +1,103 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +/** + * 买家信息表(CtBuyer)表实体类 详情Detail -刷单信息模块使用 + * + * @author rch + * @since 2022-09-20 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtBuyerClickFarmVO { + + private Long id; + + /** 创建时间 */ + private String createdAt; + + /** 修改时间 */ + private String updatedAt; + + /** 昵称*/ + private String nickName; + + /** 账号*/ + private String account; + + /** 密码*/ + private String pwd; + + /** 平台名称 */ + private Integer platformId; + + /** 平台名称 */ + private String platformName; + + /** 平台名称 */ + private Integer companyId; + + /** 公司名称 */ + private String companyName; + + /** 操作人账号*/ + private String gmName; + + ////////////////////////////////////// 新增字段 + /** 国家 */ + private String contntryShort; + /** VPN_ID(导入excel里包含) */ + private Long vpnId; + private String ipAddress; + private String link; + + /** 信用卡ID */ + private Long cardId; + private String number; + private String pinNumber; + private String holderSurname; + private String holderName; + + /** 用户等级(导入默认内部账号) 1.普通 2.精品 3.压力 4.内部账号 */ + private Integer level; + /** 占用状态 1.已占用 2.未占用 */ + private Integer occupyStatus; + /** 占用账户 */ + private String occupyAccount; + /** 账户余额 */ + private BigDecimal balance; + /** 账户购买总金额 */ + private BigDecimal buyTotalMoney; + + /** 状态(导入默认正常) 1.待注册 2待验证 3.待完善 4.正常 5.异常 6.可用但已用 7.删除 */ + private Integer status; + + // ==================地址信息相关========================================begin + /** 地址1 */ + private String addressline1; + /** 国家 */ + private String country; + /** 州 */ + private String state; + /** 电话 */ + private String tel; + /** lastname */ + private String lastname; + /** 税号 */ + private String vatNumber; + /** 城市 */ + private String city; + /** 地址2 */ + private String addressline2; + /** firstname */ + private String firstname; + /** 邮政编码 */ + private String postalcode; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBuyerDetailVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBuyerDetailVO.java new file mode 100644 index 0000000..12f1baf --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBuyerDetailVO.java @@ -0,0 +1,162 @@ +package me.zhengjie.service.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +/** + * 买家信息表(CtBuyer)表实体类 详情Detail + * + * @author rch + * @since 2022-07-07 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("买家详情") +public class CtBuyerDetailVO { + + @ApiModelProperty(value = "id") + private Long id; + + /** 创建时间 */ + @ApiModelProperty(value = "创建时间") + private String createdAt; + + /** 修改时间 */ + @ApiModelProperty(value = "修改时间") + private String updatedAt; + + /** 昵称 */ + @ApiModelProperty(value = "昵称") + private String nickName; + + /** 账号 */ + @ApiModelProperty(value = "账号") + private String account; + + /** 密码 */ + @ApiModelProperty(value = "密码") + private String pwd; + + /** 平台ID */ + @ApiModelProperty(value = "平台ID") + private Integer platformId; + + /** 平台名称 */ + @ApiModelProperty(value = "平台名称") + private String platformName; + + /** 公司ID */ + @ApiModelProperty(value = "公司ID") + private Integer companyId; + + /** 公司名称 */ + @ApiModelProperty(value = "公司名称") + private String companyName; + + /** 操作人账号*/ + @ApiModelProperty(value = "操作人账号") + private String gmName; + + ////////////////////////////////////// 新增字段 + /** 国家 */ + @ApiModelProperty(value = "国家") + private String contntryShort; + + /** VPN_ID(导入excel里包含) */ + @ApiModelProperty(value = "VPN_ID") + private Long vpnId; + + @ApiModelProperty(value = "Vpn-Ip") + private String ipAddress; + + @ApiModelProperty(value = "vpn分享链接") + private String vpn; + + /** 信用卡ID */ + @ApiModelProperty(value = "信用卡ID") + private Long cardId; + + @ApiModelProperty(value = "信用卡卡号") + private String number; + + @ApiModelProperty(value = "信用卡密码") + private String cardPwd; + + @ApiModelProperty(value = "信用卡姓氏") + private String holderSurname; + + @ApiModelProperty(value = "信用卡名称") + private String holderName; + + /** 用户等级(导入默认内部账号) 1.普通 2.精品 3.压力 4.内部账号 */ + @ApiModelProperty(value = "用户等级(导入默认内部账号) 1.普通 2.精品 3.压力 4.内部账号") + private Integer level; + + /** 占用状态 1.已占用 2.未占用 */ + @ApiModelProperty(value = "占用状态 1.已占用 2.未占用") + private Integer occupyStatus; + + /** 占用账户 */ + @ApiModelProperty(value = "占用账户") + private String occupyAccount; + + /** 账户余额 */ + @ApiModelProperty(value = "账户余额") + private BigDecimal balance; + + /** 账户购买总金额 */ + @ApiModelProperty(value = "账户购买总金额") + private BigDecimal buyTotalMoney; + + /** 状态(导入默认正常) 1.待注册 2待验证 3.待完善 4.正常 5.异常 6.可用但已用 7.删除 */ + @ApiModelProperty(value = "状态(导入默认正常) 1.待注册 2待验证 3.待完善 4.正常 5.异常 6.可用但已用 7.删除") + private Integer status; + + // ==================地址信息相关========================================begin + /** 地址1 */ + @ApiModelProperty(value = "地址1") + private String addressline1; + + /** 国家 */ + @ApiModelProperty(value = "国家") + private String country; + + /** 州 */ + @ApiModelProperty(value = "州") + private String state; + + /** 电话 */ + @ApiModelProperty(value = "电话") + private String tel; + + /** lastname */ + @ApiModelProperty(value = "lastname") + private String lastname; + + /** 税号 */ + @ApiModelProperty(value = "税号") + private String vatNumber; + + /** 城市 */ + @ApiModelProperty(value = "城市") + private String city; + + /** 地址2 */ + @ApiModelProperty(value = "地址2") + private String addressline2; + + /** firstname */ + @ApiModelProperty(value = "firstname") + private String firstname; + + /** 邮政编码 */ + @ApiModelProperty(value = "邮政编码") + private String postalcode; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBuyerListVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBuyerListVO.java new file mode 100644 index 0000000..b6a7f57 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBuyerListVO.java @@ -0,0 +1,111 @@ +package me.zhengjie.service.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 买家信息表(CtBuyer)表实体类 分页查询Detail + * + * @author rch + * @since 2022-07-07 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel +public class CtBuyerListVO { + + @ApiModelProperty(value = "Id") + private Long id; + + /** 创建时间 */ + @ApiModelProperty(value = "创建时间") + private String createdAt; + + /** 修改时间 */ + @ApiModelProperty(value = "修改时间") + private String updatedAt; + + /** 昵称 */ + @ApiModelProperty(value = "昵称") + private String nickName; + + /** 账号 */ + @ApiModelProperty(value = "账号") + private String account; + + /** 密码 */ + @ApiModelProperty(value = "密码") + private String pwd; + + /** 平台id */ + @ApiModelProperty(value = "平台id") + private Integer platformId; + + /** 平台名称 */ + @ApiModelProperty(value = "平台名称") + private String platformName; + + /** 公司id */ + @ApiModelProperty(value = "公司id") + private Long companyId; + + /** 公司名称 */ + @ApiModelProperty(value = "公司名称") + private String companyName; + + /** 操作人账号*/ + @ApiModelProperty(value = "操作人账号") + private String gmName; + + ////////////////////////////////////// 新增字段 + /** 国家 */ + @ApiModelProperty(value = "国家") + private String contntryShort; + + /** VPN_ID(导入excel里包含) */ + @ApiModelProperty(value = "VPN_ID") + private Long vpnId; + + @ApiModelProperty(value = "Vpn-Ip") + private String ipAddress; + + @ApiModelProperty(value = "vpn分享链接") + private String vpn; + + /** 信用卡ID */ + @ApiModelProperty(value = "信用卡ID") + private Long cardId; + + @ApiModelProperty(value = "信用卡卡号") + private String number; + + @ApiModelProperty(value = "信用卡密码") + private String cardPwd; + + @ApiModelProperty(value = "信用卡姓氏") + private String holderSurname; + + @ApiModelProperty(value = "信用卡名称") + private String holderName; + + /** 状态(导入默认正常) 1.待注册 2待验证 3.待完善 4.正常 5.异常 6.可用但已用 7.删除 */ + @ApiModelProperty(value = "状态(导入默认正常) 1.待注册 2待验证 3.待完善 4.正常 5.异常 6.可用但已用 7.删除") + private Integer status; + + /** 地址1 */ + @ApiModelProperty(value = "地址1") + private String addressline1; + + /** 国家 */ + @ApiModelProperty(value = "国家") + private String country; + + /** 州 */ + @ApiModelProperty(value = "州") + private String state; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBuyerVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBuyerVO.java new file mode 100644 index 0000000..efa7e74 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtBuyerVO.java @@ -0,0 +1,47 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 买家信息表(CtBuyer)表实体类 + * + * @author rch + * @since 2022-06-22 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtBuyerVO { + + private Long id; + + /** 创建时间 */ + private String createdAt; + + /** 修改时间 */ + private String updatedAt; + + /** 昵称*/ + private String nickName; + + /** 账号*/ + private String account; + + /** 密码*/ + private String pwd; + + /** 平台id */ + private Integer platformId; + + /** 平台名称 */ + private String platformName; + + /** 公司id */ + private Long companyId; + + /** 操作人账号*/ + private String gmName; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtCardDetailVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtCardDetailVO.java new file mode 100644 index 0000000..270a99b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtCardDetailVO.java @@ -0,0 +1,125 @@ +package me.zhengjie.service.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * 信用卡信息表(CtCard)表实体类 详情Detail + * + * @author rch + * @since 2022-07-09 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("信用卡详情") +public class CtCardDetailVO { + + @ApiModelProperty(value = "Id") + private Long id; + + @ApiModelProperty(value = "创建时间") + private String createdAt; + + @ApiModelProperty(value = "修改时间") + private String updatedAt; + + /** 操作人账号*/ + @ApiModelProperty(value = "操作人账号") + private String gmName; + + /** 父ID */ + @ApiModelProperty(value = "父ID") + private Long parentId; + + /** 卡号 */ + @ApiModelProperty(value = "卡号") + private String number; + +// /** PIN码 */ +// @ApiModelProperty(value = "PIN码") +// private String pinNumber; + + /** 持卡人姓氏 */ + @ApiModelProperty(value = "持卡人姓氏") + private String holderSurname; + + /** 持卡人名称 */ + @ApiModelProperty(value = "持卡人名称") + private String holderName; + + /** 有效期 */ + @ApiModelProperty(value = "有效期") + private Date termOfValidity; + + /** 余额 */ + @ApiModelProperty(value = "余额") + private BigDecimal balance; + + /** 累计消费 */ + @ApiModelProperty(value = "累计消费") + private BigDecimal sumConsume; + + /** 开卡日期 */ + @ApiModelProperty(value = "开卡日期") + private Date openDate; + + /** 所属国家 */ + @ApiModelProperty(value = "所属国家") + private String contntryShort; + + /** 信用卡类型 1.Payoneer 2.万事达虚拟卡 3.Visa信用卡 */ + @ApiModelProperty(value = "信用卡类型 1.Payoneer 2.万事达虚拟卡 3.Visa信用卡") + private Integer type; + + /** 所属厂商:1.AmzKeys 2.Airwallex */ + @ApiModelProperty(value = "所属厂商:1.AmzKeys 2.Airwallex") + private Integer cardDealer; + + /** 身份证号 */ + @ApiModelProperty(value = "身份证号") + private String idNumber; + + /** 省份 */ + @ApiModelProperty(value = "省份") + private String province; + + /** 城市 */ + @ApiModelProperty(value = "城市") + private String country; + + /** 地址 */ + @ApiModelProperty(value = "地址") + private String address; + + /** 手机号 */ + @ApiModelProperty(value = "手机号") + private String phone; + + /** 邮箱 */ + @ApiModelProperty(value = "邮箱") + private String email; + + /** 登陆账号 */ + @ApiModelProperty(value = "登陆账号") + private String account; + + /** 密码 */ + @ApiModelProperty(value = "密码") + private String pwd; + + /** 状态:1.正常、2.异常、3.已删除 */ + @ApiModelProperty(value = "状态:1.正常、2.异常、3.已删除") + private Integer status; + + /** 备注 */ + @ApiModelProperty(value = "备注") + private String remarks; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtCardListVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtCardListVO.java new file mode 100644 index 0000000..fd2225f --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtCardListVO.java @@ -0,0 +1,72 @@ +package me.zhengjie.service.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +/** + * 买家信息表(CtCard)表实体类 分页查询Detail + * + * @author rch + * @since 2022-07-09 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel +public class CtCardListVO { + + @ApiModelProperty(value = "Id") + private Long id; + + @ApiModelProperty(value = "创建时间") + private String createdAt; + + @ApiModelProperty(value = "修改时间") + private String updatedAt; + + /** 操作人账号*/ + @ApiModelProperty(value = "操作人账号") + private String gmName; + + /** 卡号 */ + @ApiModelProperty(value = "卡号") + private String number; + + /** PIN码 */ + @ApiModelProperty(value = "PIN码") + private String pinNumber; + + /** 持卡人姓氏 */ + @ApiModelProperty(value = "持卡人姓氏") + private String holderSurname; + + /** 持卡人名称 */ + @ApiModelProperty(value = "持卡人名称") + private String holderName; + + /** 余额 */ + @ApiModelProperty(value = "余额") + private BigDecimal balance; + + /** 累计消费 */ + @ApiModelProperty(value = "累计消费") + private BigDecimal sumConsume; + + /** 信用卡类型 1.Payoneer 2.万事达虚拟卡 3.Visa信用卡 */ + @ApiModelProperty(value = "信用卡类型 1.Payoneer 2.万事达虚拟卡 3.Visa信用卡") + private Integer type; + + /** 所属厂商:1.AmzKeys 2.Airwallex */ + @ApiModelProperty(value = "所属厂商:1.AmzKeys 2.Airwallex") + private Integer cardDealer; + + /** 状态:1.正常、2.异常、3.已删除 */ + @ApiModelProperty(value = "状态:1.正常、2.异常、3.已删除") + private Integer status; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickFarmEditDetailVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickFarmEditDetailVO.java new file mode 100644 index 0000000..c789a85 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickFarmEditDetailVO.java @@ -0,0 +1,63 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * 刷单Excel信息(CtClickFarming)表实体类 - 修改详情 + * + * @author rch + * @since 2022-08-16 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtClickFarmEditDetailVO { + + private Long id; + /** 关联刷单订单ID */ + private Long ctClickOrderId; + /** 买家id */ + private Long buyerId; + /** 买家名称 */ + private String buyerName; + /** 刷单类型 */ + private Integer type; + /** 刷单类型 */ + private Integer paramsType; + /** 店铺名称 */ + private String shopName; + /** 关键词 */ + private String keyWord; + /** 标题 */ + private String title; + /** 链接 */ + private String link; + /** 数量 */ + private Integer number; + /** 规格 */ + private String specification; + /** 颜色 */ + private String color; + /** item */ + private String item; + private String exchange; + /** 执行结果 */ + private String response; + /** 支付订单ID */ + private String payOrderId; + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 */ + private Integer status; + /** 留言 */ + private String amessage; + /** 创建时间 */ + private Date createdAt; + /** 修改时间 */ + private Date updatedAt; + /** 操作人账号 */ + private String gmName; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickFarmingDetailVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickFarmingDetailVO.java new file mode 100644 index 0000000..eacd156 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickFarmingDetailVO.java @@ -0,0 +1,98 @@ +package me.zhengjie.service.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.Date; + +/** + * 刷单Excel信息(CtClickFarming)表实体类 + * + * @author rch + * @since 2022-08-16 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("刷单详情") +public class CtClickFarmingDetailVO { + + @ApiModelProperty(value = "id") + private Long id; + + @ApiModelProperty(value = "买家名称") + private String buyerName; + + /** 商品属性类型 */ + @ApiModelProperty(value = "商品属性类型:1.关键词 2.链接", required = true, allowableValues = "1,2") + private Integer paramsType; + + /** 店铺名称 */ + @ApiModelProperty(value = "店铺名称") + private String shopName; + + /** 关键词 */ + @ApiModelProperty(value = "关键词") + private String keyWord; + + /** 标题 */ + @ApiModelProperty(value = "标题") + private String title; + + /** 链接 */ + @ApiModelProperty(value = "链接") + private String link; + + /** 数量 */ + @ApiModelProperty(value = "数量") + private Integer number; + + /** 规格 */ + @ApiModelProperty(value = "规格") + private String specification; + + /** 颜色 */ + @ApiModelProperty(value = "颜色") + private String color; + + /** item */ + @ApiModelProperty(value = "item") + private String item; + + @ApiModelProperty(value = "优惠劵") + private String exchange; + + /** 执行结果 */ + @ApiModelProperty(value = "执行结果") + private String response; + + /** 支付订单ID */ + @ApiModelProperty(value = "支付订单ID") + private String payOrderId; + + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 5.代付款 6.支付成功后失败 */ + @ApiModelProperty(value = "状态 1.待执行 2.执行中 3.执行成功 4.执行失败 5.代付款 6.支付成功后失败", allowableValues = "1,2,3,4,5,6") + private Integer status; + + /** 留言 */ + @ApiModelProperty(value = "留言") + private String amessage; + + /** 创建时间 */ + @ApiModelProperty(value = "创建时间") + private Date createdAt; + + /** 修改时间 */ + @ApiModelProperty(value = "修改时间") + private Date updatedAt; + + /** 操作人账号 */ + @ApiModelProperty(value = "操作人账号") + private String gmName; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickFarmingVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickFarmingVO.java new file mode 100644 index 0000000..44a409e --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickFarmingVO.java @@ -0,0 +1,59 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * 刷单Excel信息(CtClickFarming)表实体类 + * + * @author rch + * @since 2022-08-16 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtClickFarmingVO { + + private Long id; + /** 关联刷单订单ID */ + private Long ctClickOrderId; + /** 刷单类型 */ + private Integer paramsType; + /** 国家 */ + private String country; + /** 账号 */ + private String account; + /** 店铺名称 */ + private String shopName; + /** 关键词 */ + private String keyWord; + /** 标题 */ + private String title; + /** 链接 */ + private String link; + /** 数量 */ + private Integer number; + /** 规格 */ + private String specification; + /** 颜色 */ + private String color; + /** item */ + private String item; + private String exchange; + /** 执行结果 */ + private String response; + /** 支付订单ID */ + private String payOrderId; + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 */ + private Integer status; + /** 创建时间 */ + private Date createdAt; + /** 修改时间 */ + private Date updatedAt; + /** 操作人账号 */ + private String gmName; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickOrderDetailVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickOrderDetailVO.java new file mode 100644 index 0000000..1fbf249 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickOrderDetailVO.java @@ -0,0 +1,48 @@ +package me.zhengjie.service.vo; + +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; + +/** + * 刷单-订单信息(CtClickOrder)表实体类 + * + * @author rch + * @since 2022-09-14 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtClickOrderDetailVO extends Model { + private Long id; + private String createdAt; + private String updatedAt; + /** 操作人账号*/ + private String gmName; + /** 公司ID */ + private Long companyId; + /** 状态描述 */ + private String paymentResults; + /** 购买数量 */ + private String pricesNumber; + /** 总金额 */ + private String amount; + /** 店铺名称 */ + private String shop; + /** 订单id */ + private String orderId; + /** 商品名称 */ + private String shopName; + /** 时间 */ + private String orderDate; + /** 评论 */ + private String comment; + /** 图片路径 */ + private String paths; + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 */ + private Integer status; + /** 执行结果 */ + private String response; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickOrderListVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickOrderListVO.java new file mode 100644 index 0000000..f99a5b8 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtClickOrderListVO.java @@ -0,0 +1,45 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.utils.excel.ExcelExport; + +/** + * 实体类 分页查询Detail + * + * @author rch + * @since 2022-09-27 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtClickOrderListVO { + + private Long id; + private String createdAt; + private String updatedAt; + /** 公司ID */ + private Long companyId; + /** 类型 1.刷单 2.导入 */ + private Integer type; + /** 公司Name */ + private String companyName; + /** 账号 */ + private String account; + /** 密码 */ + private String pwd; + /** 总金额 */ + private String amount; + /** 店铺名称 */ + private String shop; + /** 订单id */ + private String orderId; + /** 评论 */ + private String comment; + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 */ + private Integer status; + /** 执行结果 */ + private String response; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtCompanyInfoVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtCompanyInfoVO.java new file mode 100644 index 0000000..6f1db4b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtCompanyInfoVO.java @@ -0,0 +1,23 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 公司信息(CtPlatform)表实体类 VO + * + * @author rch + * @since 2022-07-07 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtCompanyInfoVO { + + private Long id; + + /** 名称 */ + private String name; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtCompanyVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtCompanyVO.java new file mode 100644 index 0000000..c13e35d --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtCompanyVO.java @@ -0,0 +1,35 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 公司信息(CtCompany)表实体类 VO + * + * @author rch + * @since 2022-06-28 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtCompanyVO { + + private Long id; + private String createdAt; + private String updatedAt; + /** 名称 */ + private String name; + /** 地址 */ + private String address; + /** 电话 */ + private String phone; + /** 商户码(公司调用api公司唯一标识) */ + private String number; + /** 商户token(公司调用api公司token身份标识) */ + private String token; + + /** 操作人账号*/ + private String gmName; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtDhPayDetailVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtDhPayDetailVO.java new file mode 100644 index 0000000..d6f4e98 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtDhPayDetailVO.java @@ -0,0 +1,40 @@ +package me.zhengjie.service.vo; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * 买家信息表(CtDhPay)表实体类 详情Detail + * + * @author rch + * @since 2022-07-28 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtDhPayDetailVO { + + private Long id; + private String createdAt; + private String updatedAt; + /** 操作人账号*/ + private String gmName; + + /** 买家名称 */ + private String buyerName; + /** 支付订单ID(敦煌的) */ + private String orderId; + /** 请求响应详情 */ + private String response; + /** 状态 0.待处理 1.支付成功 2.支付失败 */ + private Integer status; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtDhPayListVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtDhPayListVO.java new file mode 100644 index 0000000..778ea07 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtDhPayListVO.java @@ -0,0 +1,36 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * 买家信息表(CtDhPay)表实体类 分页查询Detail + * + * @author rch + * @since 2022-07-07 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtDhPayListVO { + + private Long id; + /** 买家名称 */ + private String buyerName; + /** 支付订单ID(敦煌的) */ + private String orderId; + /** 请求响应详情 */ + private String response; + /** 状态 0.待处理 1.支付成功 2.支付失败 */ + private Integer status; + /** 创建时间 */ + private Date createdAt; + /** 修改时间 */ + private Date updatedAt; + /** 操作人账号 */ + private String gmName; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtExcelImportInfoVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtExcelImportInfoVO.java new file mode 100644 index 0000000..c20eda1 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtExcelImportInfoVO.java @@ -0,0 +1,42 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * ExcelImportInfo 导入信息(CtExcel)表实体类 VO + * + * @author rch + * @since 2022-06-27 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtExcelImportInfoVO { + + private Long id; + private String createdAt; + private String updatedAt; + + /** 公司主键 */ + private Long companyId; + + /** 鉴权枚举 */ + private Integer tokenEnum; + + /** 订单来源 */ + private String fromDetailInfo; + + /** 状态 状态 1.待处理 2.处理成功 3.处理失败 */ + private Integer status; + + /** 产品信息-JSON */ + private String cartList; + + /** 订单收货地址-JSON */ + private String contactInfo; + + /** 操作人账号*/ + private String gmName; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtExcelVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtExcelVO.java new file mode 100644 index 0000000..802664b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtExcelVO.java @@ -0,0 +1,31 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Excel 导入信息(CtExcel)表实体类 VO + * + * @author rch + * @since 2022-06-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtExcelVO { + + private Long id; + private String createdAt; + private String updatedAt; + /** 备注 */ + private String remarks; + /** excel路径 */ + private String path; + private String errorPath; + /** 状态1.待处理 2.已处理 */ + private Integer status; + + /** 操作人账号*/ + private String gmName; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtOrderVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtOrderVO.java new file mode 100644 index 0000000..2fe99ae --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtOrderVO.java @@ -0,0 +1,44 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * (CtOrder)表实体类 VO + * + * @author rch + * @since 2022-07-01 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtOrderVO { + + private Long id; + private String createdAt; + private String updatedAt; + /** 公司Id */ + private Long companyId; + /** ExcelId 信息 */ + private Long excelInfoId; + /** 买家buy_access_token */ + private String buyAccessToken; + /** 我们平台订单编号 */ + private String ctOrderNo; + /** 订单号,下单成功响应的订单号(冗余字段 下单成功响应订单信息里有) */ + private Long orderNo; + /** 下单成功响应的产品id( a,b,c 格式) (响应字段很多,先少些几个) */ + private Long responseProductId; + /** 下单成功响应的订单地址id(响应字段很多,先少些几个) */ + private Long responseOrderAddressId; + /** 下单成功响应的订单信息 (响应字段很多,先少些几个) */ + private Long responseOrderId; + /** 响应码信息 */ + private OrderResponStatusVO orderResponseStatus; + /** 响应码信息 */ + private PayOrderVO payOrderVO; + /** 状态 1.待支付(下单成功) 2.支付成功 3.支付失败*/ + private Integer status; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtPlatformInfoVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtPlatformInfoVO.java new file mode 100644 index 0000000..6086629 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtPlatformInfoVO.java @@ -0,0 +1,23 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 平台信息(CtPlatform)表实体类 VO + * + * @author rch + * @since 2022-06-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtPlatformInfoVO { + + private Long id; + + /** 名称 */ + private String name; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtPlatformVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtPlatformVO.java new file mode 100644 index 0000000..6562b7b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtPlatformVO.java @@ -0,0 +1,29 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 平台信息(CtPlatform)表实体类 VO + * + * @author rch + * @since 2022-06-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtPlatformVO { + + private Long id; + private String createdAt; + private String updatedAt; + /** 名称 */ + private String name; + /** 地址 */ + private String address; + /** 电话 */ + private String phone; + private String gmName; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtRebotListVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtRebotListVO.java new file mode 100644 index 0000000..02edb77 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtRebotListVO.java @@ -0,0 +1,37 @@ +package me.zhengjie.service.vo; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 影刀机器人 分页查询VO + * + * @Author zhw + * @Date 2022-07-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtRebotListVO { + + + private Long id; + + private String createdAt; + + private String updatedAt; + /** 操作人账号*/ + private String gmName; + + /** 机器人账号 */ + private String accountName; + /** 机器人Uuid信息 */ + private String robotClientUuid; + /** 状态 0.未占用 1.已占用 */ + private Integer status; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtVpnInfoVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtVpnInfoVO.java new file mode 100644 index 0000000..3241d22 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtVpnInfoVO.java @@ -0,0 +1,16 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtVpnInfoVO { + + private Long id; + + /** 名称 */ + private String name; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/CtVpnVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtVpnVO.java new file mode 100644 index 0000000..a95a195 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/CtVpnVO.java @@ -0,0 +1,42 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtVpnVO { + + private Long id; + /** 创建时间*/ + private String createdAt; + /** 修改时间*/ + private String updatedAt; + /** 操作人账号*/ + private String gmName; + + /** 所属国家简称 */ + private String contntryShort; + /** IP地址 */ + private String ipAddress; + /** 父ip地址 */ + private String parentIpAddress; + /** 端口 */ + private Integer port; + /** 名称 */ + private String name; + /** 密码 */ + private String pwd; + /** VPS类型 1.传统 */ + private Integer vpsType; + /** 经销商 1.V2 */ + private Integer dealer; + /** mac地址 */ + private String mac; + /** 链接 */ + private String link; + /** 经销商 1.可用 2.禁用 */ + private Integer status; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/GoogleAuthInfoVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/GoogleAuthInfoVO.java new file mode 100644 index 0000000..e99241f --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/GoogleAuthInfoVO.java @@ -0,0 +1,27 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + *

+ * 秘钥信息 + *

+ * + * @author: rch + * @since: 2020-08-26 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class GoogleAuthInfoVO { + /** 用户信息 */ + private String userName; + + /** 二维码url 信息 */ + private String qrBarCodeUrl; + + /** 明文秘钥 */ + private String secret; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/LoginIpVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/LoginIpVO.java new file mode 100644 index 0000000..80b4c10 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/LoginIpVO.java @@ -0,0 +1,57 @@ +package me.zhengjie.service.vo; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.entity.LoginIp; +import me.zhengjie.utils.DateUtil; + +import java.time.LocalDateTime; + +/* + * + * @Description + * @Date 2022/3/21 + * @Author zeng + */ +@Data +@NoArgsConstructor +public class LoginIpVO extends LoginIp { + + // 状态 1:正常 0:失效 + private Integer status; + + + public String getIp() { + StringBuffer sbf = new StringBuffer(getIpStart()); + if (sbf.length() > 0) { + sbf.append("~"); + } + sbf.append(getIpEnd()); + return sbf.toString(); + } + + public Integer getStatus() { + if (ObjectUtil.isNotEmpty(getVaildTime())) { + LocalDateTime localDateTime = DateUtil.parseLocalDateTimeFormatyMdHms(getVaildTime()); + if (localDateTime.isBefore(LocalDateTime.now())) { + return 0; + } + return 1; + } + return 1; + } + + public LoginIpVO(LoginIp loginIp) { + setId(loginIp.getId()); + setIpStart(loginIp.getIpStart()); + setIpEnd(loginIp.getIpEnd()); + setCreatedAt(loginIp.getCreatedAt()); + setUpdatedAt(loginIp.getUpdatedAt()); + setGmName(loginIp.getGmName()); + setRemark(loginIp.getRemark()); + setVaildTime(loginIp.getVaildTime()); + } + + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/OrderResponStatusVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/OrderResponStatusVO.java new file mode 100644 index 0000000..73ed2c5 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/OrderResponStatusVO.java @@ -0,0 +1,21 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 订单下单模块响应Status对象VO + * + * @author rch + * @create 2022-06-27 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class OrderResponStatusVO { + private String code; + private String message; + private String solution; + private OrderResponSubErrorVO subErrors; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/OrderResponSubErrorVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/OrderResponSubErrorVO.java new file mode 100644 index 0000000..fcf8b58 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/OrderResponSubErrorVO.java @@ -0,0 +1,19 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 敦煌接口响应SubError + * + * @author rch + * @create 2022-06-27 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class OrderResponSubErrorVO { + private String code; + private String message; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/OrderResponseVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/OrderResponseVO.java new file mode 100644 index 0000000..7c69e07 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/OrderResponseVO.java @@ -0,0 +1,28 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 敦煌订单下单响应订单信息 + * + * @author rch + * @create 2022-06-27 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class OrderResponseVO { + + /** 接口响应订单信息 订单信息 */ + private BuyOrderResponseOrderVO orderInfo; + + /** 接口响应订单信息 订单产品信息 */ + private List cartList; + + /** 接口响应订单信息 订单收件地址信息 */ + private BuyOrderResponseAddressVO orderContactInfo; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/PayOrderVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/PayOrderVO.java new file mode 100644 index 0000000..d623fdc --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/PayOrderVO.java @@ -0,0 +1,23 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 支付下单API响应对象 + * + * @author rch + * @create 2022-06-27 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class PayOrderVO { + + /** 接口响应状态 响应码 响应内容等信息*/ + private OrderResponStatusVO status; + /** 接口响应订单信息 */ + private String result; + private String message; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/SettingSiteVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/SettingSiteVO.java new file mode 100644 index 0000000..afa4d11 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/SettingSiteVO.java @@ -0,0 +1,31 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 站点配置(SettingSiteVO)表 响应类 + * + * @author zeng + * @since 2020-07-13 10:07:39 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SettingSiteVO { + + private Long id; + + /** 设置KEY */ + private String settingKey; + + /** 设置value */ + private String settingValue; + + /** 中文描述 */ + private String content; + + /** 单位 */ + private String unit; +} \ No newline at end of file diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/SysQuartzJobListVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/SysQuartzJobListVO.java new file mode 100644 index 0000000..282b4a6 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/SysQuartzJobListVO.java @@ -0,0 +1,40 @@ +package me.zhengjie.service.vo; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 影刀任务表(sys_quartz_job)表实体类 分页查询VO + * @author zhw + * @since 2022-07-21 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SysQuartzJobListVO { + + /** 任务ID */ + private Long jobId; + /** 任务名称 */ + private String jobName; + /** Spring Bean名称 */ + private String beanName; + /** 方法名称 */ + private String methodName; + /** 参数 */ + private String params; + /** cron 表达式 */ + private String cronExpression; + /** 状态:1暂停、0启用 */ + private Integer isPause; + /** 备注 */ + private String description; + /** 创建时间 */ + private String createTime; + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/SysQuartzLogListVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/SysQuartzLogListVO.java new file mode 100644 index 0000000..8b79777 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/SysQuartzLogListVO.java @@ -0,0 +1,47 @@ +package me.zhengjie.service.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.sql.Timestamp; + +/** + * 买家信息表(sys_quartz_log)表实体类 分页查询Detail + * + * @author rch + * @since 2022-07-09 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SysQuartzLogListVO { + + private Long logId; + /** bean名称 */ + private String beanName; + /** 任务名称 */ + private String jobName; + /** 方法名称 */ + private String methodName; + + /** 参数 */ + private String params; + + /** cron表达式 */ + private String cronExpression; + + /** 状态 */ + private Integer isSuccess; + + /** 异常详情 */ + private String exceptionDetail; + + /** 执行耗时 */ + private Long time; + + /** 创建时间 */ + private Timestamp createTime; +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/dhaddcar/DhAddCarListVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/dhaddcar/DhAddCarListVO.java new file mode 100644 index 0000000..b8ea1ec --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/dhaddcar/DhAddCarListVO.java @@ -0,0 +1,80 @@ +package me.zhengjie.service.vo.dhaddcar; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.util.Date; + +/** + * 敦煌加购信息 DTO + * + * @author rch + * @create 2022-11-17 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("敦煌加购信息") +public class DhAddCarListVO { + + /** ID */ + @ApiModelProperty(value = "ID", required = true) + private Long id; + + /** 商品属性类型:1.关键词 2.链接 */ + @ApiModelProperty(value = "商品属性类型:1.关键词 2.链接", required = true, allowableValues = "1,2") + private Integer paramsType; + + /** 买家ID */ + @ApiModelProperty(value = "买家ID", required = true) + private Integer buyerId; + + /** 账号 */ + @ApiModelProperty(value = "账号") + private String account; + + /** 公司名称 */ + @ApiModelProperty(value = "公司名称") + private String companyName; + + /** 国家 */ + @ApiModelProperty(value = "国家") + private String country; + + /** 加购物车商品ids */ + @ApiModelProperty(value = "加购物车商品ids") + private String carGoodIds; + + /** 执行结果 */ + @ApiModelProperty(value = "执行结果") + private String response; + + /** 状态 1.待执行 2.执行中 3.加购成功 4.加购失败 5.下单成功 6.支付成功 7.抓单成功 8.抓单失败 */ + @ApiModelProperty(value = "状态 1.待执行 2.执行中 3.加购成功 4.加购失败 5.下单成功 6.支付成功 7.抓单成功 8.抓单失败") + private Integer status; + + /** 创建时间 */ + @ApiModelProperty(value = "创建时间") + private Date createdAt; + + /** 修改时间 */ + @ApiModelProperty(value = "修改时间") + private Date updatedAt; + + /** 操作人账号 */ + @ApiModelProperty(value = "操作人账号") + private String gmName; + +// /** 加购物车商品ids */ +// @ApiModelProperty(value = "加购物车商品ids") +// private List carGoodKeys; +// +// /** 加购物车商品ids */ +// @ApiModelProperty(value = "加购物车商品ids") +// private List carGoodLinks; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/dhaddcar/DhAddCarVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/dhaddcar/DhAddCarVO.java new file mode 100644 index 0000000..1db1917 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/dhaddcar/DhAddCarVO.java @@ -0,0 +1,65 @@ +package me.zhengjie.service.vo.dhaddcar; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.service.vo.dhcargood.DhCarGoodKeyVO; +import me.zhengjie.service.vo.dhcargood.DhCarGoodLinkVO; + +import java.util.List; + +/** + * 敦煌加购Exit信息 DTO + * + * @author rch + * @create 2022-07-09 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("修改敦煌加购信息回显") +public class DhAddCarVO { + + /** ID */ + @ApiModelProperty(value = "ID", required = true) + private Long id; + + /** 商品属性类型:1.关键词 2.链接 */ + @ApiModelProperty(value = "商品属性类型:1.关键词 2.链接") + private Integer paramsType; + @ApiModelProperty(value = "公司名称", required = true) + private String companyName; + /** 买家ID */ + @ApiModelProperty(value = "买家ID", required = true) + private Integer buyerId; + /** 买家账号 */ + @ApiModelProperty(value = "买家账号", required = true) + private String account; + /** 国家 */ + @ApiModelProperty(value = "国家", required = true) + private String country; + /** 密码 */ + @ApiModelProperty(value = "密码", required = true) + private String pwd; + /** vpn分享链接 */ + private String vpnShare; + + /** 加购物车商品ids */ + @ApiModelProperty(value = "加购物车商品ids") + private String carGoodIds; + + /** 加购物车商品ids */ + @ApiModelProperty(value = "加购物车商品ids") + private List carGoodKeys; + + /** 加购物车商品ids */ + @ApiModelProperty(value = "加购物车商品ids") + private List carGoodLinks; + + /** 状态 1.待执行 2.执行中 3.加购成功 4.加购失败 5.下单成功 6.支付成功 7.抓单成功 8.抓单失败 */ + @ApiModelProperty(value = "状态 1.待执行 2.执行中 3.加购成功 4.加购失败 5.下单成功 6.支付成功 7.抓单成功 8.抓单失败") + private Integer status; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/dhaddcar/DhAddCarYdParamsVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/dhaddcar/DhAddCarYdParamsVO.java new file mode 100644 index 0000000..acd8943 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/dhaddcar/DhAddCarYdParamsVO.java @@ -0,0 +1,56 @@ +package me.zhengjie.service.vo.dhaddcar; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.service.vo.dhcargood.DhCarGoodKeyVO; +import me.zhengjie.service.vo.dhcargood.DhCarGoodLinkVO; + +import java.util.List; + +/** + * 敦煌加购 影刀参数信息 DTO + * + * @author rch + * @create 2022-07-09 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("修改敦煌加购信息回显") +public class DhAddCarYdParamsVO { + + /** ID */ + @ApiModelProperty(value = "ID", required = true) + private Long id; + + /** 商品属性类型:1.关键词 2.链接 */ + @ApiModelProperty(value = "商品属性类型:1.关键词 2.链接") + private Integer paramsType; + + /** 买家账号 */ + @ApiModelProperty(value = "买家账号", required = true) + private String account; + + /** 国家 */ + @ApiModelProperty(value = "国家", required = true) + private String country; + + /** 密码 */ + @ApiModelProperty(value = "密码", required = true) + private String pwd; + + /** vpn分享链接 */ + private String vpnShare; + + /** 加购物车商品ids */ + @ApiModelProperty(value = "加购物车商品ids") + private List carGoodKeys; + + /** 加购物车商品ids */ + @ApiModelProperty(value = "加购物车商品ids") + private List carGoodLinks; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/dhcargood/DhCarGoodKeyVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/dhcargood/DhCarGoodKeyVO.java new file mode 100644 index 0000000..3c8a789 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/dhcargood/DhCarGoodKeyVO.java @@ -0,0 +1,76 @@ +package me.zhengjie.service.vo.dhcargood; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Null; + +/** + * 敦煌-加购商品(根据关键词) VO + * + * @author rch + * @create 2022-07-09 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("敦煌-加购商品(根据关键词)") +public class DhCarGoodKeyVO { + + /** ID */ + @ApiModelProperty(value = "ID", required = true) + private Long id; + + /** 商品属性类型:1.关键词 2.链接 */ + @ApiModelProperty(value = "商品属性类型:1.关键词 2.链接", required = true, allowableValues = "1,2") + private Integer paramsType; + + /** 店铺名称 */ + @ApiModelProperty(value = "NotBlank", required = true) + private String shopName; + + /** 关键词 */ + @ApiModelProperty(value = "关键词", required = true) + private String keyWord; + + /** 标题 */ + @ApiModelProperty(value = "标题", required = true) + private String title; + + /** 数量 */ + @ApiModelProperty(value = "数量", required = true) + private Integer number; + + /** 规格 */ + @ApiModelProperty(value = "规格") + private String specification; + + /** 颜色 */ + @ApiModelProperty(value = "颜色") + private String color; + + /** item */ + @ApiModelProperty(value = "item", required = true) + private String item; + + /** 最小价格区间 */ + @ApiModelProperty(value = "最小价格区间") + private String sectionMin; + + /** 最大价格区间 */ + @ApiModelProperty(value = "最大价格区间") + private String sectionMax; + + /** 评论 */ + @ApiModelProperty(value = "评论") + private String comment; + + /** 图片url */ + @ApiModelProperty(value = "图片url") + private String paths; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/dhcargood/DhCarGoodLinkVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/dhcargood/DhCarGoodLinkVO.java new file mode 100644 index 0000000..0a6005e --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/dhcargood/DhCarGoodLinkVO.java @@ -0,0 +1,56 @@ +package me.zhengjie.service.vo.dhcargood; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Null; + +/** + * 敦煌-加购商品(根据链接) VO + * + * @author rch + * @create 2022-07-09 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("敦煌-加购商品(根据链接)") +public class DhCarGoodLinkVO { + + /** ID */ + @ApiModelProperty(value = "ID", required = true) + private Long id; + + /** 商品属性类型:1.关键词 2.链接 */ + @ApiModelProperty(value = "商品属性类型:1.关键词 2.链接", required = true, allowableValues = "1,2") + private Integer paramsType; + + /** 链接 */ + @ApiModelProperty(value = "链接", required = true) + private String link; + + /** 数量 */ + @ApiModelProperty(value = "数量", required = true) + private Integer number; + + /** 规格 */ + @ApiModelProperty(value = "规格", required = true) + private String specification; + + /** 颜色 */ + @ApiModelProperty(value = "颜色", required = true) + private String color; + + /** 评论 */ + @ApiModelProperty(value = "评论") + private String comment; + + /** 图片url */ + @ApiModelProperty(value = "图片url") + private String paths; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/dhcarorder/DhAddCarOrderListVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/dhcarorder/DhAddCarOrderListVO.java new file mode 100644 index 0000000..c8920e4 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/dhcarorder/DhAddCarOrderListVO.java @@ -0,0 +1,62 @@ +package me.zhengjie.service.vo.dhcarorder; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * 敦煌加购订单信息 DTO + * + * @author rch + * @create 2022-12-01 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("敦煌加购信息") +public class DhAddCarOrderListVO { + + @ApiModelProperty(value = "ID") + private Long id; + @ApiModelProperty(value = "创建时间") + private String createdAt; + @ApiModelProperty(value = "修改时间") + private String updatedAt; + /** 操作人账号*/ + @ApiModelProperty(value = "操作人") + private String gmName; + + /** 1.导入 2.刷单 */ + @ApiModelProperty(value = "类型 1.导入 2.刷单") + private Integer type; + /** 关联敦煌加购的id */ + @ApiModelProperty(value = "关联敦煌加购的id") + private Long addCarId; + /** 总金额 */ + @ApiModelProperty(value = "总金额") + private String amount; + /** 状态描述 */ + @ApiModelProperty(value = "状态描述") + private String paymentResults; + /** 店铺名称 */ + @ApiModelProperty(value = "店铺名称") + private String shop; + /** 订单id */ + @ApiModelProperty(value = "订单id") + private String orderId; + /** 时间 */ + @ApiModelProperty(value = "订单时间") + private String orderDate; + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 */ + @ApiModelProperty(value = "状态 1.待执行 2.执行中 3.执行成功 4.执行失败") + private Integer status; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/service/vo/dhcarorder/DhCarOrderParamsVO.java b/wjcy-common/src/main/java/me/zhengjie/service/vo/dhcarorder/DhCarOrderParamsVO.java new file mode 100644 index 0000000..ad98173 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/service/vo/dhcarorder/DhCarOrderParamsVO.java @@ -0,0 +1,59 @@ +package me.zhengjie.service.vo.dhcarorder; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.service.vo.dhcargood.DhCarGoodKeyVO; +import me.zhengjie.service.vo.dhcargood.DhCarGoodLinkVO; + +import java.util.List; + +/** + * 敦煌加购好评-影刀参数 + * + * @author rch + * @create 2022-12-01 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DhCarOrderParamsVO { + /** ID */ + @ApiModelProperty(value = "ID", required = true) + private Long id; + + /** 商品属性类型:1.关键词 2.链接 */ + @ApiModelProperty(value = "商品属性类型:1.关键词 2.链接") + private Integer paramsType; + + /** 买家账号 */ + @ApiModelProperty(value = "买家账号", required = true) + private String account; + + /** 国家 */ + @ApiModelProperty(value = "国家", required = true) + private String country; + + /** 密码 */ + @ApiModelProperty(value = "密码", required = true) + private String pwd; + + /** vpn分享链接 */ + private String vpnShare; + + /** 订单ID */ + private String orderId; + + /** 加购物车商品ids */ + @ApiModelProperty(value = "加购物车商品ids") + private String carGoodIds; + + /** 加购物车商品ids */ + @ApiModelProperty(value = "加购物车商品ids") + private List carGoodKeys; + + /** 加购物车商品ids */ + @ApiModelProperty(value = "加购物车商品ids") + private List carGoodLinks; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/CacheKey.java b/wjcy-common/src/main/java/me/zhengjie/utils/CacheKey.java new file mode 100644 index 0000000..7485713 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/CacheKey.java @@ -0,0 +1,58 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils; + +/** + * @author: liaojinlong + * @date: 2020/6/11 15:49 + * @apiNote: 关于缓存的Key集合 + */ +public interface CacheKey { + + /** + * 用户 + */ + String USER_ID = "user::id:"; + /** + * 数据 + */ + String DATA_USER = "data::user:"; + /** + * 菜单 + */ + String MENU_ID = "menu::id:"; + String MENU_USER = "menu::user:"; + /** + * 角色授权 + */ + String ROLE_AUTH = "role::auth:"; + /** + * 角色信息 + */ + String ROLE_ID = "role::id:"; + /** + * 部门 + */ + String DEPT_ID = "dept::id:"; + /** + * 岗位 + */ + String JOB_ID = "job::id:"; + /** + * 数据字典 + */ + String DICT_NAME = "dict::name:"; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/CallBack.java b/wjcy-common/src/main/java/me/zhengjie/utils/CallBack.java new file mode 100644 index 0000000..9b10812 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/CallBack.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zhengjie.utils; + +/** + * @author: liaojinlong + * @date: 2020/6/9 17:02 + * @since: 1.0 + * @see {@link SpringContextHolder} + * 针对某些初始化方法,在SpringContextHolder 初始化前时,
+ * 可提交一个 提交回调任务。
+ * 在SpringContextHolder 初始化后,进行回调使用 + */ + +public interface CallBack { + /** + * 回调执行方法 + */ + void executor(); + + /** + * 本回调任务名称 + * @return / + */ + default String getCallBackName() { + return Thread.currentThread().getId() + ":" + this.getClass().getName(); + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/CheckPwdValidator.java b/wjcy-common/src/main/java/me/zhengjie/utils/CheckPwdValidator.java new file mode 100644 index 0000000..2f10dca --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/CheckPwdValidator.java @@ -0,0 +1,35 @@ +package me.zhengjie.utils; + +import cn.hutool.core.util.ObjectUtil; +import me.zhengjie.annotation.CheckPwd; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.util.regex.Pattern; + +/* + * + * @Description + * @Date 2022/3/21 + * @Author zeng + */ +public class CheckPwdValidator implements ConstraintValidator { + + private CheckPwd checkPwd; + + public static final String p = "^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[~@#$%\\*-\\+=:,\\\\?\\[\\]\\{}]).{16,64}$"; + + + @Override + public void initialize(CheckPwd constraintAnnotation) { + this.checkPwd = constraintAnnotation; + } + + @Override + public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { + if (ObjectUtil.isEmpty(value)) { + return true; + } + return Pattern.matches(p, value); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/CloseUtil.java b/wjcy-common/src/main/java/me/zhengjie/utils/CloseUtil.java new file mode 100644 index 0000000..98d375b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/CloseUtil.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils; + +import java.io.Closeable; + +/** + * @author Zheng Jie + * @website https://el-admin.vip + * @description 用于关闭各种连接,缺啥补啥 + * @date 2021-03-05 + **/ +public class CloseUtil { + + public static void close(Closeable closeable) { + if (null != closeable) { + try { + closeable.close(); + } catch (Exception e) { + // 静默关闭 + } + } + } + + public static void close(AutoCloseable closeable) { + if (null != closeable) { + try { + closeable.close(); + } catch (Exception e) { + // 静默关闭 + } + } + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/CronUtils.java b/wjcy-common/src/main/java/me/zhengjie/utils/CronUtils.java new file mode 100644 index 0000000..14728f8 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/CronUtils.java @@ -0,0 +1,49 @@ +package me.zhengjie.utils; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * 时间日期转cron工具类 + * Spring Task是Quartz的弱版,Quartz支持年份,而Spring Task不支持。Spring Task是6位, + * Quartz可以7位,本代码是基于hutool工具的表达式,是可以支持Quartz。 + * @author rch + * @create 2022-10-06 + */ +public class CronUtils { + + + /** + * 仅一次 + * @param dateStr + * @return + */ + public static String onlyOnce(String dateStr) { + LocalDateTime time = LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + String cronStr = time.format(DateTimeFormatter.ofPattern("ss mm HH dd MM ? yyyy")); + return cronStr; + } + + /** + * 每天 + * @param timeStr + * @return + */ + public static String everyDay(String timeStr) { + LocalDateTime time = LocalDateTime.parse(timeStr, DateTimeFormatter.ofPattern("HH:mm:ss")); + String cronStr = time.format(DateTimeFormatter.ofPattern("ss mm HH dd * * ?")); + return cronStr; + } + + + /** + * 每周 + * @param timeStr + * @return + */ + public static String everyWeek(String timeStr, String week) { + LocalDateTime time = LocalDateTime.parse(timeStr, DateTimeFormatter.ofPattern("HH:mm:ss")); + String cronStr = time.format(DateTimeFormatter.ofPattern("ss mm HH ? * " + week)); + return cronStr; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/DateTimeValidator.java b/wjcy-common/src/main/java/me/zhengjie/utils/DateTimeValidator.java new file mode 100644 index 0000000..1d22b75 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/DateTimeValidator.java @@ -0,0 +1,46 @@ +package me.zhengjie.utils; + + +import cn.hutool.core.util.ObjectUtil; +import me.zhengjie.annotation.DateTime; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.text.SimpleDateFormat; +/** + *

+ * 日期格式效验 + *

+ * + * @Author xx + * @Date 2021/7/27 + **/ +public class DateTimeValidator implements ConstraintValidator { + private DateTime dateTime; + + @Override + public void initialize(DateTime dateTime) { + this.dateTime = dateTime; + } + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + if (ObjectUtil.isEmpty(value)) { + return true; + } + String format = dateTime.format(); + + if (value.length() != format.length()) { + return false; + } + + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format); + + try { + simpleDateFormat.parse(value); + } catch (Exception e) { + return false; + } + return true; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/DateUtil.java b/wjcy-common/src/main/java/me/zhengjie/utils/DateUtil.java new file mode 100644 index 0000000..3df2210 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/DateUtil.java @@ -0,0 +1,555 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zhengjie.utils; + +import cn.hutool.core.util.ObjectUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.*; +import java.time.format.DateTimeFormatter; +import java.util.*; + +/** + * @author: liaojinlong + * @date: 2020/6/11 16:28 + * @apiNote: JDK 8 新日期类 格式化与字符串转换 工具类 + */ +public class DateUtil { + + private static final Logger LOGGER = LoggerFactory.getLogger(DateUtil.class); + + public static final DateTimeFormatter DFY_MD_HMS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + public static final DateTimeFormatter DFY_MD = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + + /** + * + * 判断某个时间是否在某个时间段内 + * @ xxs + * @param date 待比较的时间 + * @param format 时间格式,eg("HH:mm") + * @param startTimeStr 时间范围的开始时间,eg("06:00") + * @param endTimeStr 时间范围的结束时间,eg("22:00") + * + * */ + public static Boolean isBelong(Date date, String format, String startTimeStr, String endTimeStr){ + //设置日期格式 + SimpleDateFormat df = new SimpleDateFormat(format); + Date beginTime = null; + Date endTime = null; + try { + date = df.parse(df.format(date)); + beginTime = df.parse(startTimeStr); + endTime = df.parse(endTimeStr); + } catch (Exception e) { + e.printStackTrace(); + } + + return belongCalendar(date, beginTime, endTime); + } + + + + /** + * 判断时间是否在时间段内 + * @xxs + * @param nowTime + * @param beginTime + * @param endTime + * @return + */ + public static boolean belongCalendar(Date nowTime, Date beginTime, Date endTime) { + Calendar date = Calendar.getInstance(); + date.setTime(nowTime); + + Calendar begin = Calendar.getInstance(); + begin.setTime(beginTime); + + Calendar end = Calendar.getInstance(); + end.setTime(endTime); + + if (date.after(begin) && date.before(end)) { + return true; + } else { + return false; + } + } + + /** + * 比较两日期格式大小(最新的时间靠前) + * 1: time1time2 + * 0: time1=time2 + * null time1 or time2 日期格式错误 + * + * @param time1 yyyy-MM-dd HH:mm:ss + * @param time2 yyyy-MM-dd HH:mm:ss + * @return + */ + public static Integer compareDate(String time1, String time2) { + try { + LocalDateTime t1 = parseLocalDateTimeFormatyMdHms(time1); + LocalDateTime t2 = parseLocalDateTimeFormatyMdHms(time2); + Long timeStamp1 = getTimeStamp(t1); + Long timeStamp2 = getTimeStamp(t2); + if (timeStamp1 < timeStamp2) { + return 1; + } + if (timeStamp1 > timeStamp2) { + return -1; + } + if (timeStamp1.equals(timeStamp2)) { + return 0; + } + } catch (Exception e) {} + return null; + } + + /** + * 获得指定日期的前一天 + * + * @param specifiedDay + * @return + * @throws Exception + */ + public static String getSpecifiedDayBefore(String specifiedDay) { + Calendar c = Calendar.getInstance(); + Date date = null; + try { + date = new SimpleDateFormat("yy-MM-dd").parse(specifiedDay); + } catch (ParseException e) { + e.printStackTrace(); + } + c.setTime(date); + int day = c.get(Calendar.DATE); + c.set(Calendar.DATE, day - 1); + + String dayBefore = new SimpleDateFormat("yyyy-MM-dd").format(c.getTime()); + return dayBefore; + } + + /** + * 获取今日查询时间 + * + * @return + */ + public static Map getTodayDate(String time) { + Map map = new HashMap(16); + map.put("stime", time + " 00:00:00"); + map.put("etime", time + " 23:59:59"); + return map; + } + + + /** + * 根据发送时间获取有效截止时间 + * + * @param sendTime yyyy-MM-dd HH:mm:ss + * @param days 有效天数 + * @return + */ + public static LocalDate getExpiryDate(String sendTime, Integer days) { + if (ObjectUtil.isEmpty(sendTime)) { + sendTime = getCurrentTime(); + } + return LocalDate.parse(sendTime, DFY_MD_HMS) + .plusDays(days); + } + + /** + * 将年月日时分秒的各种转为cron表达式 + * + * @param time + * @return + */ + public static String toCronString(String time) { + LocalDateTime dateTime = LocalDateTime.parse(time, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + return dateTime.getSecond() + " " + dateTime.getMinute() + " " + dateTime.getHour() + " " + + dateTime.getDayOfMonth() + " " + dateTime.getMonthValue() + " ? " + dateTime.getYear(); + } + + /** + * 获取当时时间 yyyy-MM-dd HH:mm:ss格式 + * + * @return + */ + public static String getCurrentTime() { + return localDateTimeFormatyMdHms(LocalDateTime.now()); + } + + /** + * 获取系统当前时间 + * + * @return 系统当前时间(年月日) + */ + public static String getCurrentDateHalf() { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + String date = simpleDateFormat.format(new Date()); + return date; + } + /** + * 获取系统未来某天的日期 + * + * @return 系统昨天时间(年月日) + */ + public static String getFutrueDateHalf(Integer day) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + String date = simpleDateFormat.format(new Date()); + Calendar calendar = new GregorianCalendar(); + calendar.setTime(new Date()); + calendar.add(Calendar.DATE, day); + return simpleDateFormat.format(calendar.getTime()); + } + /** + * 获取系统前12小时时间 + * + * @return 系统前12小时时间(年月日) + */ + public static String getCurrentTimeBeforeTwHour() { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String date = simpleDateFormat.format(new Date()); + Calendar calendar = new GregorianCalendar(); + calendar.setTime(new Date()); + calendar.add(Calendar.HOUR, -12); + return simpleDateFormat.format(calendar.getTime()); + } + /** + * 获取系统昨天时间 + * + * @return 系统昨天时间(年月日) + */ + public static String getYesterDateHalf() { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + String date = simpleDateFormat.format(new Date()); + Calendar calendar = new GregorianCalendar(); + calendar.setTime(new Date()); + calendar.add(Calendar.DATE, -1); + return simpleDateFormat.format(calendar.getTime()); + } + /** + * 获取系统昨天时间 + * + * @return 系统昨天时间(年月日) + */ + public static String getAgoDateHalf(int i) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + String date = simpleDateFormat.format(new Date()); + Calendar calendar = new GregorianCalendar(); + calendar.setTime(new Date()); + calendar.add(Calendar.DATE, -i); + return simpleDateFormat.format(calendar.getTime()); + } + /** + * 获取系统昨天时间 + * + * @return 系统昨天时间(年月日) + */ + public static String getWeekAgoDateHalf() { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + String date = simpleDateFormat.format(new Date()); + Calendar calendar = new GregorianCalendar(); + calendar.setTime(new Date()); + calendar.add(Calendar.DATE, -7); + return simpleDateFormat.format(calendar.getTime()); + } + /** + * 获取当时时间+10min yyyy-MM-dd HH:mm:ss格式 + * + * @return + */ + public static String getCurrentTimeAddTenMin() { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String date = simpleDateFormat.format(new Date()); + Calendar calendar = new GregorianCalendar(); + calendar.setTime(new Date()); + calendar.add(Calendar.MINUTE, 10); + return simpleDateFormat.format(calendar.getTime()); + } + + /**获取后两分钟 + * @param startTime + * @return + */ + public static String getLaterTimeAddTwoMin(String startTime){ + + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Calendar calendar = new GregorianCalendar(); + try { + + calendar.setTime(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(startTime)); + calendar.add(Calendar.MINUTE, 2); + } catch (Exception exception) { + LOGGER.error(exception.getMessage()); + } + return simpleDateFormat.format(calendar.getTime()); + } + /**获取前一天 + * @param startTime + * @return + */ + public static String getAgoTimeAddDay(String startTime){ + + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Calendar calendar = new GregorianCalendar(); + try { + + calendar.setTime(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(startTime)); + calendar.add(Calendar.HOUR, -24); + } catch (Exception exception) { + LOGGER.error(exception.getMessage()); + } + return simpleDateFormat.format(calendar.getTime()); + } + /**获取后一天 + * @param startTime + * @return + */ + public static String getLaterTimeAddDay(String startTime){ + + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Calendar calendar = new GregorianCalendar(); + try { + + calendar.setTime(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(startTime)); + calendar.add(Calendar.HOUR, 24); + } catch (Exception exception) { + LOGGER.error(exception.getMessage()); + } + return simpleDateFormat.format(calendar.getTime()); + } + /** 获取前十分钟 时间 + * @param startTime + * @return + */ + public static String getEarlyTimeAddTenMin(String startTime){ + + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Calendar calendar = new GregorianCalendar(); + try { + + calendar.setTime(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(startTime)); + calendar.add(Calendar.MINUTE, -10); + } catch (Exception exception) { + LOGGER.error(exception.getMessage()); + } + return simpleDateFormat.format(calendar.getTime()); + } + + /** + * LocalDateTime 转时间戳 + * + * @param localDateTime / + * @return / + */ + public static Long getTimeStamp(LocalDateTime localDateTime) { + return localDateTime.atZone(ZoneId.systemDefault()).toEpochSecond(); + } + + /** + * 时间戳转LocalDateTime + * + * @param timeStamp / + * @return / + */ + public static LocalDateTime fromTimeStamp(Long timeStamp) { + return LocalDateTime.ofEpochSecond(timeStamp, 0, OffsetDateTime.now().getOffset()); + } + + /** + * LocalDateTime 转 Date + * Jdk8 后 不推荐使用 {@link Date} Date + * + * @param localDateTime / + * @return / + */ + public static Date toDate(LocalDateTime localDateTime) { + return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); + } + + /** + * LocalDate 转 Date + * Jdk8 后 不推荐使用 {@link Date} Date + * + * @param localDate / + * @return / + */ + public static Date toDate(LocalDate localDate) { + return toDate(localDate.atTime(LocalTime.now(ZoneId.systemDefault()))); + } + + + /** + * Date转 LocalDateTime + * Jdk8 后 不推荐使用 {@link Date} Date + * + * @param date / + * @return / + */ + public static LocalDateTime toLocalDateTime(Date date) { + return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()); + } + + /** + * 日期 格式化 + * + * @param localDateTime / + * @param patten / + * @return / + */ + public static String localDateTimeFormat(LocalDateTime localDateTime, String patten) { + DateTimeFormatter df = DateTimeFormatter.ofPattern(patten); + return df.format(localDateTime); + } + + /** + * 日期 格式化 + * + * @param localDateTime / + * @param df / + * @return / + */ + public static String localDateTimeFormat(LocalDateTime localDateTime, DateTimeFormatter df) { + return df.format(localDateTime); + } + + /** + * 日期格式化 yyyy-MM-dd HH:mm:ss + * + * @param localDateTime / + * @return / + */ + public static String localDateTimeFormatyMdHms(LocalDateTime localDateTime) { + return DFY_MD_HMS.format(localDateTime); + } + + /** + * 日期格式化 yyyy-MM-dd + * + * @param localDateTime / + * @return / + */ + public String localDateTimeFormatyMd(LocalDateTime localDateTime) { + return DFY_MD.format(localDateTime); + } + + /** + * 字符串转 LocalDateTime ,字符串格式 yyyy-MM-dd + * + * @param localDateTime / + * @return / + */ + public static LocalDateTime parseLocalDateTimeFormat(String localDateTime, String pattern) { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern); + return LocalDateTime.from(dateTimeFormatter.parse(localDateTime)); + } + + /** + * 字符串转 LocalDateTime ,字符串格式 yyyy-MM-dd + * + * @param localDateTime / + * @return / + */ + public static LocalDateTime parseLocalDateTimeFormat(String localDateTime, DateTimeFormatter dateTimeFormatter) { + return LocalDateTime.from(dateTimeFormatter.parse(localDateTime)); + } + + /** + * 字符串转 LocalDateTime ,字符串格式 yyyy-MM-dd HH:mm:ss + * + * @param localDateTime / + * @return / + */ + public static LocalDateTime parseLocalDateTimeFormatyMdHms(String localDateTime) { + return LocalDateTime.from(DFY_MD_HMS.parse(localDateTime)); + } + + /** + * 字符串转 LocalDate ,字符串格式 yyyy-MM-dd + * @param localDate + * @return + */ + public static LocalDate parseLocalDateFormatyMd(String localDate) { + return LocalDate.from(DFY_MD.parse(localDate)); + } + + /** + * 生成指定时间之前相聚 指定秒的一个时间并返回 + * 时间格式默认常规 年月日 时分秒: 2020-12-07 10:18:25 + * @param endTime + * @param min 相聚多少秒 + * @param max + * @return + */ + public static String getRandmo(String endTime, Integer min, Integer max) { + + if (min > max) { + return null; + } + + try { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); + Date endTimeDate = format.parse(endTime); + Random random = new Random(); + long time = random.nextInt(max - min + 1) + min; + Date newDate = new Date(endTimeDate .getTime() - time * 1000); + return format.format(newDate); + }catch (Exception exception) { + return null; + } + } + + /** + * @Description: 获取当天日期再查询日期区间的第几个位置,起始位置从0开始算 + * @Author: zeng + * @param stime + * @param etime + * @return: java.lang.Integer + */ + public static Long getDifferenceDayCount(String stime,String etime) { + if (!ObjectUtil.isAllNotEmpty(stime, etime)) { + return null; + } + LocalDate sLocalDate = parseLocalDateTimeFormatyMdHms(stime).toLocalDate(); + LocalDate eLocalDate = parseLocalDateTimeFormatyMdHms(etime).toLocalDate(); + + return Math.abs(eLocalDate.toEpochDay() - sLocalDate.toEpochDay())+1; + } + + + public static String getHour(long dt) { + //秒数 +// Integer dt = Integer.parseInt(date) ; + if (dt < 3600) { + return Math.round(dt / 60) + "分钟"; + } + int hour = Math.round(dt / 3600); + int minute = Math.round((dt - (hour * 3600)) / 60); + long s = dt - (hour == 0 ? 0 : hour * 3600) - (minute == 0 ? 0 : minute * 60); + return hour == 0 ? "" : hour + "小时" + (minute == 0 ? "" : minute + "分钟") + (s == 0 ? "" : s + "秒"); + + //分钟 +// Integer dt = Integer.parseInt(date) ; +// if (dt < 60) return dt + "分钟"; +// int hour = Math.round(dt / 60); +// int minute = Math.round(dt - (hour * 60)); +// return hour + "小时" + (minute == 0 ? "" : minute + "分钟"); + } + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/ElAdminConstant.java b/wjcy-common/src/main/java/me/zhengjie/utils/ElAdminConstant.java new file mode 100644 index 0000000..08f9c3c --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/ElAdminConstant.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils; + +/** + * 常用静态常量 + * + * @author Zheng Jie + * @date 2018-12-26 + */ +public class ElAdminConstant { + + /** + * 用于IP定位转换 + */ + public static final String REGION = "内网IP|内网IP"; + /** + * win 系统 + */ + public static final String WIN = "win"; + + /** + * mac 系统 + */ + public static final String MAC = "mac"; + + /** + * 常用接口 + */ + public static class Url { + // IP归属地查询 + public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp?ip=%s&json=true"; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/EmptyAttributeFiler.java b/wjcy-common/src/main/java/me/zhengjie/utils/EmptyAttributeFiler.java new file mode 100644 index 0000000..c7fdd93 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/EmptyAttributeFiler.java @@ -0,0 +1,76 @@ +package me.zhengjie.utils; + + +import cn.hutool.core.util.ObjectUtil; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.util.List; +/** + *

+ * 将数据为空或空字符串的过滤为null(MyBatis 会将空字符串的值也持久化到数据库中) + *

+ * + * @Author xx + * @Date 2021/7/19 + **/ +@Slf4j +public class EmptyAttributeFiler { + + /** + * 判断list的所有元素是否都为null + * @param list + * @return + */ + public static boolean isEmpty(List list) { + if (ObjectUtil.isEmpty(list)) { + return true; + } + for (Object o : list) { + if (ObjectUtil.isNotEmpty(o)) { + return false; + } + } + return true; + } + + public static T emptyAttributeFiler(T obj) { + Class clazz = obj.getClass(); + Field[] fields = clazz.getDeclaredFields(); + try { + for (Field field : fields) { + field.setAccessible(true); + if (ObjectUtil.isEmpty(field.get(obj))) { + field.set(obj, null); + } + } + } catch (Exception e) { + log.error("过滤值为空属性失败:" + e.getMessage(), e); + } + return obj; + } + + public static String emptyAttributeFilerToString(Object obj) { + Class clazz = obj.getClass(); + Field[] fields = clazz.getDeclaredFields(); + StringBuffer sbf = new StringBuffer("{"); + try { + int i = 0; + for (Field field : fields) { + field.setAccessible(true); + if (ObjectUtil.isNotEmpty(field.get(obj))) { + if (i != 0) { + sbf.append(","+field.getName() + ":" + field.get(obj)); + continue; + } + sbf.append(field.getName() + ":" + field.get(obj)); + i++; + } + } + } catch (Exception e) { + log.error("过滤值为空属性失败:" + e.getMessage(), e); + } + sbf.append("}"); + return sbf.toString().length()==2?"":sbf.toString(); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/EncryptUtils.java b/wjcy-common/src/main/java/me/zhengjie/utils/EncryptUtils.java new file mode 100644 index 0000000..4f334aa --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/EncryptUtils.java @@ -0,0 +1,100 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.DESKeySpec; +import javax.crypto.spec.IvParameterSpec; +import java.nio.charset.StandardCharsets; + +/** + * 加密 + * @author Zheng Jie + * @date 2018-11-23 + */ + +public class EncryptUtils { + + private static final String STR_PARAM = "Passw0rd"; + + private static Cipher cipher; + + private static final IvParameterSpec IV = new IvParameterSpec(STR_PARAM.getBytes(StandardCharsets.UTF_8)); + + private static DESKeySpec getDesKeySpec(String source) throws Exception { + if (source == null || source.length() == 0){ + return null; + } + cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); + String strKey = "Passw0rd"; + return new DESKeySpec(strKey.getBytes(StandardCharsets.UTF_8)); + } + + /** + * 对称加密 + */ + public static String desEncrypt(String source) throws Exception { + DESKeySpec desKeySpec = getDesKeySpec(source); + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); + SecretKey secretKey = keyFactory.generateSecret(desKeySpec); + cipher.init(Cipher.ENCRYPT_MODE, secretKey, IV); + return byte2hex( + cipher.doFinal(source.getBytes(StandardCharsets.UTF_8))).toUpperCase(); + } + + /** + * 对称解密 + */ + public static String desDecrypt(String source) throws Exception { + byte[] src = hex2byte(source.getBytes(StandardCharsets.UTF_8)); + DESKeySpec desKeySpec = getDesKeySpec(source); + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); + SecretKey secretKey = keyFactory.generateSecret(desKeySpec); + cipher.init(Cipher.DECRYPT_MODE, secretKey, IV); + byte[] retByte = cipher.doFinal(src); + return new String(retByte); + } + + private static String byte2hex(byte[] inStr) { + String stmp; + StringBuilder out = new StringBuilder(inStr.length * 2); + for (byte b : inStr) { + stmp = Integer.toHexString(b & 0xFF); + if (stmp.length() == 1) { + // 如果是0至F的单位字符串,则添加0 + out.append("0").append(stmp); + } else { + out.append(stmp); + } + } + return out.toString(); + } + + private static byte[] hex2byte(byte[] b) { + int size = 2; + if ((b.length % size) != 0){ + throw new IllegalArgumentException("长度不是偶数"); + } + byte[] b2 = new byte[b.length / 2]; + for (int n = 0; n < b.length; n += size) { + String item = new String(b, n, 2); + b2[n / 2] = (byte) Integer.parseInt(item, 16); + } + return b2; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/FileUtil.java b/wjcy-common/src/main/java/me/zhengjie/utils/FileUtil.java new file mode 100644 index 0000000..e8577d0 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/FileUtil.java @@ -0,0 +1,351 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.poi.excel.BigExcelWriter; +import cn.hutool.poi.excel.ExcelUtil; +import me.zhengjie.exception.BadRequestException; +import org.apache.poi.util.IOUtils; +import org.apache.poi.xssf.streaming.SXSSFSheet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.security.MessageDigest; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * File工具类,扩展 hutool 工具包 + * + * @author Zheng Jie + * @date 2018-12-27 + */ +public class FileUtil extends cn.hutool.core.io.FileUtil { + + private static final Logger log = LoggerFactory.getLogger(FileUtil.class); + + /** + * 系统临时目录 + *
+ * windows 包含路径分割符,但Linux 不包含, + * 在windows \\==\ 前提下, + * 为安全起见 同意拼装 路径分割符, + *
+     *       java.io.tmpdir
+     *       windows : C:\Users/xxx\AppData\Local\Temp\
+     *       linux: /temp
+     * 
+ */ + public static final String SYS_TEM_DIR = System.getProperty("java.io.tmpdir") + File.separator; + /** + * 定义GB的计算常量 + */ + private static final int GB = 1024 * 1024 * 1024; + /** + * 定义MB的计算常量 + */ + private static final int MB = 1024 * 1024; + /** + * 定义KB的计算常量 + */ + private static final int KB = 1024; + + /** + * 格式化小数 + */ + private static final DecimalFormat DF = new DecimalFormat("0.00"); + + public static final String IMAGE = "图片"; + public static final String TXT = "文档"; + public static final String MUSIC = "音乐"; + public static final String VIDEO = "视频"; + public static final String OTHER = "其他"; + + + /** + * MultipartFile转File + */ + public static File toFile(MultipartFile multipartFile) { + // 获取文件名 + String fileName = multipartFile.getOriginalFilename(); + // 获取文件后缀 + String prefix = "." + getExtensionName(fileName); + File file = null; + try { + // 用uuid作为文件名,防止生成的临时文件重复 + file = new File(SYS_TEM_DIR + IdUtil.simpleUUID() + prefix); + // MultipartFile to File + multipartFile.transferTo(file); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + return file; + } + + /** + * 获取文件扩展名,不带 . + */ + public static String getExtensionName(String filename) { + if ((filename != null) && (filename.length() > 0)) { + int dot = filename.lastIndexOf('.'); + if ((dot > -1) && (dot < (filename.length() - 1))) { + return filename.substring(dot + 1); + } + } + return filename; + } + + /** + * Java文件操作 获取不带扩展名的文件名 + */ + public static String getFileNameNoEx(String filename) { + if ((filename != null) && (filename.length() > 0)) { + int dot = filename.lastIndexOf('.'); + if ((dot > -1) && (dot < (filename.length()))) { + return filename.substring(0, dot); + } + } + return filename; + } + + /** + * 文件大小转换 + */ + public static String getSize(long size) { + String resultSize; + if (size / GB >= 1) { + //如果当前Byte的值大于等于1GB + resultSize = DF.format(size / (float) GB) + "GB "; + } else if (size / MB >= 1) { + //如果当前Byte的值大于等于1MB + resultSize = DF.format(size / (float) MB) + "MB "; + } else if (size / KB >= 1) { + //如果当前Byte的值大于等于1KB + resultSize = DF.format(size / (float) KB) + "KB "; + } else { + resultSize = size + "B "; + } + return resultSize; + } + + /** + * inputStream 转 File + */ + public static File inputStreamToFile(InputStream ins, String name){ + File file = new File(SYS_TEM_DIR + name); + if (file.exists()) { + return file; + } + OutputStream os = null; + try { + os = new FileOutputStream(file); + int bytesRead; + int len = 8192; + byte[] buffer = new byte[len]; + while ((bytesRead = ins.read(buffer, 0, len)) != -1) { + os.write(buffer, 0, bytesRead); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + CloseUtil.close(os); + CloseUtil.close(ins); + } + return file; + } + + /** + * 将文件名解析成文件的上传路径 + */ + public static File upload(MultipartFile file, String filePath) { + Date date = new Date(); + SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS"); + String name = getFileNameNoEx(file.getOriginalFilename()); + String suffix = getExtensionName(file.getOriginalFilename()); + String nowStr = "-" + format.format(date); + try { + String fileName = name + nowStr + "." + suffix; + String path = filePath + fileName; + // getCanonicalFile 可解析正确各种路径 + File dest = new File(path).getCanonicalFile(); + // 检测是否存在目录 + if (!dest.getParentFile().exists()) { + if (!dest.getParentFile().mkdirs()) { + System.out.println("was not successful."); + } + } + // 文件写入 + file.transferTo(dest); + return dest; + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return null; + } + + /** + * 导出excel + */ + public static void downloadExcel(List> list, HttpServletResponse response) throws IOException { + String tempPath = SYS_TEM_DIR + IdUtil.fastSimpleUUID() + ".xlsx"; + File file = new File(tempPath); + BigExcelWriter writer = ExcelUtil.getBigWriter(file); + // 一次性写出内容,使用默认样式,强制输出标题 + writer.write(list, true); + //response为HttpServletResponse对象 + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"); + //test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码 + response.setHeader("Content-Disposition", "attachment;filename=file.xlsx"); + ServletOutputStream out = response.getOutputStream(); + // 终止后删除临时文件 + file.deleteOnExit(); + writer.flush(out, true); + //此处记得关闭输出Servlet流 + IoUtil.close(out); + } + + public static String getFileType(String type) { + String documents = "txt doc pdf ppt pps xlsx xls docx"; + String music = "mp3 wav wma mpa ram ra aac aif m4a"; + String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg"; + String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg"; + if (image.contains(type)) { + return IMAGE; + } else if (documents.contains(type)) { + return TXT; + } else if (music.contains(type)) { + return MUSIC; + } else if (video.contains(type)) { + return VIDEO; + } else { + return OTHER; + } + } + + public static void checkSize(long maxSize, long size) { + // 1M + int len = 1024 * 1024; + if (size > (maxSize * len)) { + throw new BadRequestException("文件超出规定大小"); + } + } + + /** + * 判断两个文件是否相同 + */ + public static boolean check(File file1, File file2) { + String img1Md5 = getMd5(file1); + String img2Md5 = getMd5(file2); + if(img1Md5 != null){ + return img1Md5.equals(img2Md5); + } + return false; + } + + /** + * 判断两个文件是否相同 + */ + public static boolean check(String file1Md5, String file2Md5) { + return file1Md5.equals(file2Md5); + } + + private static byte[] getByte(File file) { + // 得到文件长度 + byte[] b = new byte[(int) file.length()]; + InputStream in = null; + try { + in = new FileInputStream(file); + try { + System.out.println(in.read(b)); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; + } finally { + CloseUtil.close(in); + } + return b; + } + + private static String getMd5(byte[] bytes) { + // 16进制字符 + char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + try { + MessageDigest mdTemp = MessageDigest.getInstance("MD5"); + mdTemp.update(bytes); + byte[] md = mdTemp.digest(); + int j = md.length; + char[] str = new char[j * 2]; + int k = 0; + // 移位 输出字符串 + for (byte byte0 : md) { + str[k++] = hexDigits[byte0 >>> 4 & 0xf]; + str[k++] = hexDigits[byte0 & 0xf]; + } + return new String(str); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return null; + } + + /** + * 下载文件 + * + * @param request / + * @param response / + * @param file / + */ + public static void downloadFile(HttpServletRequest request, HttpServletResponse response, File file, boolean deleteOnExit) { + response.setCharacterEncoding(request.getCharacterEncoding()); + response.setContentType("application/octet-stream"); + FileInputStream fis = null; + try { + fis = new FileInputStream(file); + response.setHeader("Content-Disposition", "attachment; filename=" + file.getName()); + IOUtils.copy(fis, response.getOutputStream()); + response.flushBuffer(); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + if (fis != null) { + try { + fis.close(); + if (deleteOnExit) { + file.deleteOnExit(); + } + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } + } + } + + public static String getMd5(File file) { + return getMd5(getByte(file)); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/HexUtil.java b/wjcy-common/src/main/java/me/zhengjie/utils/HexUtil.java new file mode 100644 index 0000000..96cf5d5 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/HexUtil.java @@ -0,0 +1,51 @@ +package me.zhengjie.utils; + +import cn.hutool.core.util.ObjectUtil; +import static jodd.util.CharUtil.HEX_CHARS; +/** + *

+ * dy登录加密校验 + *

+ * + * @Author xx + * @Date 2021/7/21 + **/ +public class HexUtil { + + public static String toHexString(byte[] bArr, int i, int i2) { + if (bArr == null) { + throw new NullPointerException("bytes is null"); + } else if (i < 0 || i + i2 > bArr.length) { + throw new IndexOutOfBoundsException(); + } else { + int i3 = i2 * 2; + char[] cArr = new char[i3]; + int i4 = 0; + for (int i5 = 0; i5 < i2; i5++) { + int i6 = bArr[i5 + i] & 255; + int i7 = i4 + 1; + cArr[i4] = HEX_CHARS[i6 >> 4]; + i4 = i7 + 1; + cArr[i7] = HEX_CHARS[i6 & 15]; + } + return new String(cArr, 0, i3); + } + } + + + public static String encryptWithXor(String str) { + try { + if (ObjectUtil.isEmpty(str)) { + return null; + } + byte[] bytes = str.getBytes("UTF-8"); + for (int i = 0; i < bytes.length; i++) { + bytes[i] = (byte) (bytes[i] ^ 5); + } + return toHexString(bytes, 0, bytes.length); + } catch (Exception unused) { + return str; + } + } + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/HttpClientUtil.java b/wjcy-common/src/main/java/me/zhengjie/utils/HttpClientUtil.java new file mode 100644 index 0000000..618c216 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/HttpClientUtil.java @@ -0,0 +1,356 @@ +package me.zhengjie.utils; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * @author rch + * @date 2022-06-22 + */ +@Slf4j +public class HttpClientUtil { + + public static String postJson(String url, String body, String charset) { + + String result = null; + if (null == charset) { + charset = "UTF-8"; + } + CloseableHttpClient httpClient = null; + HttpPost httpPost = null; + try { + httpClient = HttpConnectionManager.getInstance().getHttpClient(); + httpPost = new HttpPost(url); + + // 设置连接超时,设置读取超时 + RequestConfig requestConfig = RequestConfig.custom() + .setConnectTimeout(3000) + .setSocketTimeout(3000) + .build(); + httpPost.setConfig(requestConfig); + + httpPost.setHeader("Accept", "application/json"); + httpPost.setHeader("Content-Type", "application/json;charset=utf-8"); + + // 设置参数 + StringEntity se = new StringEntity(body, "UTF-8"); + httpPost.setEntity(se); + HttpResponse response = httpClient.execute(httpPost); + if (response != null) { + HttpEntity resEntity = response.getEntity(); + if (resEntity != null) { + result = EntityUtils.toString(resEntity, charset); + } + } + } catch (Exception ex) { + ex.printStackTrace(); + log.error(ex.getMessage()); + } + + return result; + } + + + public static String postJson(String url, Map heards, String body, String charset) { + + String result = null; + if (null == charset) { + charset = "UTF-8"; + } + CloseableHttpClient httpClient = null; + HttpPost httpPost = null; + try { + httpClient = HttpConnectionManager.getInstance().getHttpClient(); + httpPost = new HttpPost(url); + + // 设置连接超时,设置读取超时 + RequestConfig requestConfig = RequestConfig.custom() + .setConnectTimeout(3000) + .setSocketTimeout(3000) + .build(); + httpPost.setConfig(requestConfig); + + for (Map.Entry heard:heards.entrySet()) { + httpPost.setHeader(heard.getKey(), heard.getValue().toString()); + } + + // 设置参数 + StringEntity se = new StringEntity(body, "UTF-8"); + httpPost.setEntity(se); + HttpResponse response = httpClient.execute(httpPost); + if (response != null) { + HttpEntity resEntity = response.getEntity(); + if (resEntity != null) { + result = EntityUtils.toString(resEntity, charset); + } + } + } catch (Exception ex) { + ex.printStackTrace(); + log.error(ex.getMessage()); + } + + return result; + } + + + /** + * 发送 POST 请求(HTTP),K-V形式 + * + * @param apiUrl + * API接口URL + * @param params + * 参数map + * @return + */ + public static String doPostHttp(String apiUrl, Map params) { + CloseableHttpClient httpClient = HttpClients.createDefault(); + String httpStr = null; + HttpPost httpPost = new HttpPost(apiUrl); + CloseableHttpResponse response = null; + + try { + // 设置连接超时,设置读取超时 + RequestConfig requestConfig = RequestConfig.custom() + .setConnectTimeout(10000) + .setSocketTimeout(10000) + .build(); + httpPost.setConfig(requestConfig); + httpPost.setHeader("Accept", "application/json"); + httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded"); + + List pairList = new ArrayList<>(params.size()); + for (Entry entry : params.entrySet()) { + NameValuePair pair = new BasicNameValuePair(entry.getKey(), Convert.toStr(entry.getValue())); + pairList.add(pair); + } + httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("UTF-8"))); + response = httpClient.execute(httpPost); +// System.out.println("http==response.toString():" + response.toString()); + HttpEntity entity = response.getEntity(); + httpStr = EntityUtils.toString(entity, "UTF-8"); + } catch (IOException e) { + e.printStackTrace(); + log.error(e.getMessage()); + } finally { + if (response != null) { + try { + EntityUtils.consume(response.getEntity()); + } catch (IOException e) { + e.printStackTrace(); + log.error(e.getMessage()); + } + } + } + return httpStr; + } + + /** + * 发送 GET 请求(HTTP),K-V形式 + * + * @param apiUrl + * API接口URL + * @param params + * 参数map + * @return + */ + public static String getHttp(String apiUrl,Map params){ + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + String result = ""; + try { + String url = apiUrl; + if(MapUtil.isNotEmpty(params)){ + String paramsStr = ""; + for (String key : params.keySet()) { + if(ObjectUtil.isNotEmpty(params.get(key))){ + if(StrUtil.isNotEmpty(paramsStr)){ + paramsStr += "&" + key + "=" + params.get(key); + }else{ + paramsStr += key + "=" + params.get(key); + } + } + } + if(StrUtil.isNotEmpty(paramsStr)){ + url += "?" + paramsStr; + } + } + httpClient = HttpClients.createDefault(); + System.out.println("url:" + url); + HttpGet httpGet = new HttpGet(url); + // 设置连接超时,设置读取超时 + RequestConfig requestConfig = RequestConfig.custom() + .setConnectTimeout(5000) + .setSocketTimeout(5000) + .build(); + httpGet.setConfig(requestConfig); + response = httpClient.execute(httpGet); + HttpEntity entity = response.getEntity(); + result = EntityUtils.toString(entity, "UTF-8"); + } catch (IOException e) { + e.printStackTrace(); + log.error(e.getMessage()); + } finally { + if (response != null) { + try { + response.close(); + } catch (IOException e) { + e.printStackTrace(); + log.error(e.getMessage()); + } + } + if (httpClient != null) { + try { + httpClient.close(); + } catch (IOException e) { + e.printStackTrace(); + log.error(e.getMessage()); + } + } + } + return result; + } + + + + /** + * 发送 GET 请求(HTTP) + * + * @param apiUrl + * API接口URL + * @return + */ + public static String getUrlHttp(String apiUrl){ + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + String result = ""; + try { + String url = apiUrl; + httpClient = HttpClients.createDefault(); + System.out.println("url:" + url); + HttpGet httpGet = new HttpGet(url); + // 设置连接超时,设置读取超时 + RequestConfig requestConfig = RequestConfig.custom() + .setConnectTimeout(5000) + .setSocketTimeout(5000) + .build(); + httpGet.setConfig(requestConfig); + response = httpClient.execute(httpGet); + HttpEntity entity = response.getEntity(); + result = EntityUtils.toString(entity, "UTF-8"); + } catch (IOException e) { + e.printStackTrace(); + log.error(e.getMessage()); + } finally { + if (response != null) { + try { + response.close(); + } catch (IOException e) { + e.printStackTrace(); + log.error(e.getMessage()); + } + } + if (httpClient != null) { + try { + httpClient.close(); + } catch (IOException e) { + e.printStackTrace(); + log.error(e.getMessage()); + } + } + } + return result; + } + + /** + * 发送 POST 请求(HTTP),K-V形式 + * + * @param apiUrl + * API接口URL + * @param params + * 参数map + * @return + */ + public static String postHttp(String apiUrl,Map params){ + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + String result = ""; + try { + String url = apiUrl; + httpClient = HttpClients.createDefault(); + HttpPost httpPost = new HttpPost(url); + // 设置连接超时,设置读取超时 + RequestConfig requestConfig = RequestConfig.custom() + .setConnectTimeout(5000) + .setSocketTimeout(5000) + .build(); + httpPost.setConfig(requestConfig); + if(MapUtil.isNotEmpty(params)){ + StringEntity se = new StringEntity(JSONUtil.toJsonStr(params), "UTF-8"); + se.setContentType("application/json"); + httpPost.setEntity(se); + } + response = httpClient.execute(httpPost); + HttpEntity entity = response.getEntity(); + result = EntityUtils.toString(entity, "UTF-8"); + } catch (IOException e) { + e.printStackTrace(); + log.error(e.getMessage()); + } finally { + if (response != null) { + try { + EntityUtils.consume(response.getEntity()); + } catch (IOException e) { + e.printStackTrace(); + log.error(e.getMessage()); + } + } + if (httpClient != null) { + try { + httpClient.close(); + } catch (IOException e) { + e.printStackTrace(); + log.error(e.getMessage()); + } + } + } + return result; + } + + + public static void main(String[] args) { + String url = "http://kjw.utest6.com/forcol/a"; + Map params = new HashMap<>(16); + params.put("page",1); + params.put("pageSize",10000); + params.put("beginTime","2022-04-01 21:00:00"); + + String result = postHttp(url,params); + System.out.println(result); + } + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/HttpConnectionManager.java b/wjcy-common/src/main/java/me/zhengjie/utils/HttpConnectionManager.java new file mode 100644 index 0000000..85dc9c8 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/HttpConnectionManager.java @@ -0,0 +1,57 @@ +package me.zhengjie.utils; + + +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.LayeredConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.springframework.stereotype.Component; + +import javax.net.ssl.SSLContext; +import java.security.NoSuchAlgorithmException; + +@Component +public class HttpConnectionManager { + + private PoolingHttpClientConnectionManager cm = null; + + private static HttpConnectionManager connectionManager; + + public static HttpConnectionManager getInstance() { + if (connectionManager == null) { + synchronized (HttpConnectionManager.class) { + if (connectionManager == null) { + connectionManager = new HttpConnectionManager(); + connectionManager.init(); + } + } + } + return connectionManager; + } + + private void init() { + LayeredConnectionSocketFactory sslsf = null; + try { + sslsf = new SSLConnectionSocketFactory(SSLContext.getDefault()); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + + Registry socketFactoryRegistry = RegistryBuilder. create() + .register("https", sslsf).register("http", new PlainConnectionSocketFactory()).build(); + cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + cm.setMaxTotal(200); + cm.setDefaultMaxPerRoute(20); + } + + public CloseableHttpClient getHttpClient() { + CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build(); + + return httpClient; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/JsonDealUtils.java b/wjcy-common/src/main/java/me/zhengjie/utils/JsonDealUtils.java new file mode 100644 index 0000000..ecf2793 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/JsonDealUtils.java @@ -0,0 +1,54 @@ +package me.zhengjie.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; + +import java.util.Iterator; +import java.util.Set; + +/** + * 递归去除Json字符串空值(key和value) + * + * @author rch + * @create 2022-06-27 + */ +public class JsonDealUtils { + + public static JSONObject getNoNullValue(String json) { + JSONObject objTem=JSON.parseObject(json); + JSONObject objRel=JSON.parseObject(json); + return deal(objTem,objRel); + } + + private static JSONObject deal(JSONObject objTem,JSONObject objRel) { + Set keySet = objTem.keySet(); + Iterator iterator = keySet.iterator(); + while(iterator.hasNext()) { + String temp = iterator.next(); + Object objR = objTem.get(temp); + if(temp==null||"".equals(temp)||"null".equals(temp)) { + objRel.remove(temp); + continue; + } + if(objR==null||"".equals(objR.toString())||"null".equals(objR.toString())||"[]".equals(objR.toString())||"{}".equals(objR.toString())) { + objRel.remove(temp); + continue; + } + if(objR instanceof JSONObject) { + JSONObject j=(JSONObject)objR; + JSONObject object2 = (JSONObject)objRel.get(temp); + deal(j,object2); + continue; + } + if(objR instanceof JSONArray) { + JSONArray jsonArray = objTem.getJSONArray(temp); + JSONArray jsonArray2 = objRel.getJSONArray(temp); + for(int i=0;i + * MD5工具类 + *

+ * + * @author: rch + * @since: 2020-12-03 + */ + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class MD5Util { + + /** * 生成16位小写md5加密字符串 * @param sourceStr * @return */ + public static String MD5ToLow16(String sourceStr) { + try { + // 获得MD5摘要算法的 MessageDigest对象 + StringBuffer buf = getMD5StringBuffer(sourceStr); + return buf.toString().substring(8, 24).toLowerCase();// 16位加密 + // return buf.toString();// 32位加密 + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** * 生成16位大写md5加密字符串 * @param sourceStr * @return */ + public static String MD5ToUpp16(String sourceStr) { + try { + // 获得MD5摘要算法的 MessageDigest对象 + StringBuffer buf = getMD5StringBuffer(sourceStr); + return buf.toString().substring(8, 24).toUpperCase();// 16位加密 + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** * 生成32位小写md5加密字符串 * @param sourceStr * @return */ + public static String MD5ToLow32(String sourceStr) { + try { + // 获得MD5摘要算法的 MessageDigest对象 + StringBuffer buf = getMD5StringBuffer(sourceStr); + return buf.toString().toLowerCase();// 32位加密 + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** * 生成32位大写md5加密字符串 * @param sourceStr * @return */ + public static String MD5ToUpp32(String sourceStr) { + try { + StringBuffer buf = getMD5StringBuffer(sourceStr); + + return buf.toString().toUpperCase();// 32位加密 + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** * 将字符串MD5加密 * @param sourceStr * @return * @throws NoSuchAlgorithmException */ + private static StringBuffer getMD5StringBuffer(String sourceStr) throws NoSuchAlgorithmException { + // 获得MD5摘要算法的 MessageDigest对象 + MessageDigest mdInst = MessageDigest.getInstance("MD5"); + // 使用指定的字节更新摘要 + mdInst.update(sourceStr.getBytes()); + // 获得密文 + byte[] md = mdInst.digest(); + // 把密文转换成十六进制的字符串形式 + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < md.length; i++) { + int tmp = md[i]; + if (tmp < 0){ + tmp += 256; + } + if (tmp < 16){ + buf.append("0"); + } + buf.append(Integer.toHexString(tmp)); + } + return buf; + } + + public static String md5(String str) { + try { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + md5.update((str).getBytes("UTF-8")); + byte b[] = md5.digest(); + + int i; + StringBuffer buf = new StringBuffer(""); + + for (int offset = 0; offset < b.length; offset++) { + i = b[offset]; + if (i < 0) { + i += 256; + } + if (i < 16) { + buf.append("0"); + } + buf.append(Integer.toHexString(i)); + } + return buf.toString(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static void main(String[] args) { +// String str = "1"; +// System.out.println(str); +// System.out.println(MD5ToLow16(str)); +// System.out.println(MD5ToLow32(str)); +// System.out.println(MD5ToUpp16(str)); +// System.out.println(MD5ToUpp32(str)); + String ttt = "sportsCe7vS3j1ziPHwfDDffJ3ivX34Z1cb2S1133687017471620710415600000004www.sportstatus.comzhU33255"; + System.out.println(md5(ttt)); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/OrderGetIndexUtil.java b/wjcy-common/src/main/java/me/zhengjie/utils/OrderGetIndexUtil.java new file mode 100644 index 0000000..8bce737 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/OrderGetIndexUtil.java @@ -0,0 +1,63 @@ +package me.zhengjie.utils; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +/** + *

+ * --顺序访问 + * 第几次访问 % 钱包池中有几个排序钱包 得到 当前应该取钱包池中钱包的索引 实现顺序访问。 + *

+ * + * @author: rch + * @date: 2021-09-25 + */ +public class OrderGetIndexUtil { + + private static Map concurrentHashMap = new ConcurrentHashMap<>(16); + + /** + * @param merId 商家id + * @return 指定钱包池中当前该取钱包id 下标索引 + */ + public static int getIncrement(Long merId, Integer walletType, Integer passType) { + + String keyStr = merId + "-" + walletType + "-" + passType; + AtomicInteger atomicInteger = new AtomicInteger(0); + + Integer current; + int next; + do { + current = concurrentHashMap.get(keyStr); + current = current != null ? current : 0; + atomicInteger = new AtomicInteger(current); + next = current >= 2147483647 ? 0 : current+1; + + }while (!atomicInteger.compareAndSet(current, next)); + + concurrentHashMap.put(keyStr, next); + System.out.println("------------第几次访问:次数next="+next); + return next; + } + + public static void main(String[] args) { + for (int i = 0; i < 10; i++) { + if (i % 5 == 0) { + System.out.println("0==" + getIncrement(1L, 1, 1)); + } else if (i % 5 == 1) { + System.out.println("1==" + getIncrement(1L, 2, 1)); + } else if (i % 5 == 2) { + System.out.println("2==" + getIncrement(2L, 1, 1)); + } else if (i % 5 == 3) { + System.out.println("2==" + getIncrement(2L, 2,1)); + } else if (i % 5 == 4) { + System.out.println("3==" + getIncrement(2L, 3,1)); + } else { + System.out.println("!2=" + getIncrement(11L, 3, 1)); + } + } + + System.out.println("2==" + getIncrement(2L, 1, 1)); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/PageUtil.java b/wjcy-common/src/main/java/me/zhengjie/utils/PageUtil.java new file mode 100644 index 0000000..44db68d --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/PageUtil.java @@ -0,0 +1,63 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils; + +import org.springframework.data.domain.Page; +import java.util.*; + +/** + * 分页工具 + * @author Zheng Jie + * @date 2018-12-10 + */ +public class PageUtil extends cn.hutool.core.util.PageUtil { + + /** + * List 分页 + */ + public static List toPage(int page, int size , List list) { + int fromIndex = page * size; + int toIndex = page * size + size; + if(fromIndex > list.size()){ + return new ArrayList(); + } else if(toIndex >= list.size()) { + return list.subList(fromIndex,list.size()); + } else { + return list.subList(fromIndex,toIndex); + } + } + + /** + * Page 数据处理,预防redis反序列化报错 + */ + public static Map toPage(Page page) { + Map map = new LinkedHashMap<>(2); + map.put("content",page.getContent()); + map.put("totalElements",page.getTotalElements()); + return map; + } + + /** + * 自定义分页 + */ + public static Map toPage(Object object, Object totalElements) { + Map map = new LinkedHashMap<>(2); + map.put("content",object); + map.put("totalElements",totalElements); + return map; + } + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/PageUtils.java b/wjcy-common/src/main/java/me/zhengjie/utils/PageUtils.java new file mode 100644 index 0000000..cbf8730 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/PageUtils.java @@ -0,0 +1,55 @@ +package me.zhengjie.utils; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.Data; + +import java.util.Collections; +import java.util.List; +/** + *

+ * 分页查询工具类 + *

+ * + * @Author xx + * @Date 2021/7/19 + **/ +@Data +public class PageUtils { + /** + * 总记录数 + */ + private Long total; + /** + * 查询结果 + */ + private List list; + + public PageUtils() { + + } + + public PageUtils(Long total, List list) { + this.total = total; + this.list = list; + } + + public PageUtils(Page page) { + this.total = page.getTotal(); + this.list = page.getRecords(); + } + + public Long getTotal() { + if (ObjectUtil.isNull(total)|| EmptyAttributeFiler.isEmpty(list)) { + return 0L; + } + return total; + } + + public List getList() { + if (EmptyAttributeFiler.isEmpty(list)) { + return Collections.emptyList(); + } + return list; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/PopularizeUtil.java b/wjcy-common/src/main/java/me/zhengjie/utils/PopularizeUtil.java new file mode 100644 index 0000000..ebb422e --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/PopularizeUtil.java @@ -0,0 +1,49 @@ +package me.zhengjie.utils; + +import cn.hutool.core.lang.UUID; + + +/** + * 推广码生成 工具类 + * + * @author: e + * @since: 2022/01/19 + */ +public class PopularizeUtil { + + public static String[] chars = new String[] { "a", "b", "c", "d", "e", "f", + "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", + "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", + "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", + "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", + "W", "X", "Y", "Z" }; + + /** + * 创建推广码 + * @return + */ + public static String createPromoCode(){ + return generateShortUuid().toUpperCase(); + //return RandomUtil.randomString(8).toUpperCase(); + } + + + public static String generateShortUuid() { + StringBuffer shortBuffer = new StringBuffer(); + String uuid = UUID.randomUUID().toString().replace("-", ""); + for (int i = 0; i < 8; i++) { + String str = uuid.substring(i * 4, i * 4 + 4); + int x = Integer.parseInt(str, 16); + shortBuffer.append(chars[x % 0x3E]); + } + return shortBuffer.toString(); + + } + + public static void main(String[] args) { + + + } + + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/PropertiesUtil.java b/wjcy-common/src/main/java/me/zhengjie/utils/PropertiesUtil.java new file mode 100644 index 0000000..3dab51b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/PropertiesUtil.java @@ -0,0 +1,62 @@ +package me.zhengjie.utils; + +import cn.hutool.core.util.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.config.SystemConfig; + +import java.io.*; +import java.util.Properties; + +/* + * + * @Description 读取多语言文本工具类 + * @Date 2021/12/16 + * @Author zeng + */ +@Slf4j +public class PropertiesUtil { + + public static String getByCode(Integer code, String language) { + FileInputStream fis = null; + InputStreamReader isr = null; + BufferedReader br = null; + try { + File file = new File(SystemConfig.LANGUAGE_PATH); + if (file.exists()) { + for (File listFile : file.listFiles()) { + if (listFile.getName().contains(language + ".properties")) { + Properties properties = new Properties(); + fis = new FileInputStream(listFile); + isr = new InputStreamReader(fis, "UTF-8"); + BufferedReader bf = new BufferedReader(isr); + properties.load(bf); + return properties.getProperty(code.toString()); + } + } + } + + } catch (FileNotFoundException e) { + log.error("文件不存在=========================="); + } catch (IOException e) { + log.error("文件读取异常=========================="); + }finally { + try { + if (ObjectUtil.isNotNull(br)) { + br.close(); + } + if (ObjectUtil.isNotNull(isr)) { + isr.close(); + } + if (ObjectUtil.isNotNull(fis)){ + fis.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + + } + log.error("=============读取多语言文本失败================== code:{} language:{}", code, language); + return null; + } + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/QueryHelp.java b/wjcy-common/src/main/java/me/zhengjie/utils/QueryHelp.java new file mode 100644 index 0000000..69cb5e2 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/QueryHelp.java @@ -0,0 +1,208 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.annotation.DataPermission; +import me.zhengjie.annotation.Query; +import javax.persistence.criteria.*; +import java.lang.reflect.Field; +import java.util.*; + +/** + * @author Zheng Jie + * @date 2019-6-4 14:59:48 + */ +@Slf4j +@SuppressWarnings({"unchecked","all"}) +public class QueryHelp { + + public static Predicate getPredicate(Root root, Q query, CriteriaBuilder cb) { + List list = new ArrayList<>(); + if(query == null){ + return cb.and(list.toArray(new Predicate[0])); + } + // 数据权限验证 + DataPermission permission = query.getClass().getAnnotation(DataPermission.class); + if(permission != null){ + // 获取数据权限 + List dataScopes = SecurityUtils.getCurrentUserDataScope(); + if(CollectionUtil.isNotEmpty(dataScopes)){ + if(StringUtils.isNotBlank(permission.joinName()) && StringUtils.isNotBlank(permission.fieldName())) { + Join join = root.join(permission.joinName(), JoinType.LEFT); + list.add(getExpression(permission.fieldName(),join, root).in(dataScopes)); + } else if (StringUtils.isBlank(permission.joinName()) && StringUtils.isNotBlank(permission.fieldName())) { + list.add(getExpression(permission.fieldName(),null, root).in(dataScopes)); + } + } + } + try { + List fields = getAllFields(query.getClass(), new ArrayList<>()); + for (Field field : fields) { + boolean accessible = field.isAccessible(); + // 设置对象的访问权限,保证对private的属性的访 + field.setAccessible(true); + Query q = field.getAnnotation(Query.class); + if (q != null) { + String propName = q.propName(); + String joinName = q.joinName(); + String blurry = q.blurry(); + String attributeName = isBlank(propName) ? field.getName() : propName; + Class fieldType = field.getType(); + Object val = field.get(query); + if (ObjectUtil.isNull(val) || "".equals(val)) { + continue; + } + Join join = null; + // 模糊多字段 + if (ObjectUtil.isNotEmpty(blurry)) { + String[] blurrys = blurry.split(","); + List orPredicate = new ArrayList<>(); + for (String s : blurrys) { + orPredicate.add(cb.like(root.get(s) + .as(String.class), "%" + val.toString() + "%")); + } + Predicate[] p = new Predicate[orPredicate.size()]; + list.add(cb.or(orPredicate.toArray(p))); + continue; + } + if (ObjectUtil.isNotEmpty(joinName)) { + String[] joinNames = joinName.split(">"); + for (String name : joinNames) { + switch (q.join()) { + case LEFT: + if(ObjectUtil.isNotNull(join) && ObjectUtil.isNotNull(val)){ + join = join.join(name, JoinType.LEFT); + } else { + join = root.join(name, JoinType.LEFT); + } + break; + case RIGHT: + if(ObjectUtil.isNotNull(join) && ObjectUtil.isNotNull(val)){ + join = join.join(name, JoinType.RIGHT); + } else { + join = root.join(name, JoinType.RIGHT); + } + break; + case INNER: + if(ObjectUtil.isNotNull(join) && ObjectUtil.isNotNull(val)){ + join = join.join(name, JoinType.INNER); + } else { + join = root.join(name, JoinType.INNER); + } + break; + default: break; + } + } + } + switch (q.type()) { + case EQUAL: + list.add(cb.equal(getExpression(attributeName,join,root) + .as((Class) fieldType),val)); + break; + case GREATER_THAN: + list.add(cb.greaterThanOrEqualTo(getExpression(attributeName,join,root) + .as((Class) fieldType), (Comparable) val)); + break; + case LESS_THAN: + list.add(cb.lessThanOrEqualTo(getExpression(attributeName,join,root) + .as((Class) fieldType), (Comparable) val)); + break; + case LESS_THAN_NQ: + list.add(cb.lessThan(getExpression(attributeName,join,root) + .as((Class) fieldType), (Comparable) val)); + break; + case INNER_LIKE: + list.add(cb.like(getExpression(attributeName,join,root) + .as(String.class), "%" + val.toString() + "%")); + break; + case LEFT_LIKE: + list.add(cb.like(getExpression(attributeName,join,root) + .as(String.class), "%" + val.toString())); + break; + case RIGHT_LIKE: + list.add(cb.like(getExpression(attributeName,join,root) + .as(String.class), val.toString() + "%")); + break; + case IN: + if (CollUtil.isNotEmpty((Collection)val)) { + list.add(getExpression(attributeName,join,root).in((Collection) val)); + } + break; + case NOT_IN: + if (CollUtil.isNotEmpty((Collection)val)) { + list.add(getExpression(attributeName,join,root).in((Collection) val).not()); + } + break; + case NOT_EQUAL: + list.add(cb.notEqual(getExpression(attributeName,join,root), val)); + break; + case NOT_NULL: + list.add(cb.isNotNull(getExpression(attributeName,join,root))); + break; + case IS_NULL: + list.add(cb.isNull(getExpression(attributeName,join,root))); + break; + case BETWEEN: + List between = new ArrayList<>((List)val); + list.add(cb.between(getExpression(attributeName, join, root).as((Class) between.get(0).getClass()), + (Comparable) between.get(0), (Comparable) between.get(1))); + break; + default: break; + } + } + field.setAccessible(accessible); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } + int size = list.size(); + return cb.and(list.toArray(new Predicate[size])); + } + + @SuppressWarnings("unchecked") + private static Expression getExpression(String attributeName, Join join, Root root) { + if (ObjectUtil.isNotEmpty(join)) { + return join.get(attributeName); + } else { + return root.get(attributeName); + } + } + + private static boolean isBlank(final CharSequence cs) { + int strLen; + if (cs == null || (strLen = cs.length()) == 0) { + return true; + } + for (int i = 0; i < strLen; i++) { + if (!Character.isWhitespace(cs.charAt(i))) { + return false; + } + } + return true; + } + + public static List getAllFields(Class clazz, List fields) { + if (clazz != null) { + fields.addAll(Arrays.asList(clazz.getDeclaredFields())); + getAllFields(clazz.getSuperclass(), fields); + } + return fields; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/RedisUtils.java b/wjcy-common/src/main/java/me/zhengjie/utils/RedisUtils.java new file mode 100644 index 0000000..c633b81 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/RedisUtils.java @@ -0,0 +1,903 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.*; +import org.springframework.data.redis.support.atomic.RedisAtomicLong; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * @author / + */ +@Component +@SuppressWarnings({"unchecked", "all"}) +public class RedisUtils { + private static final Logger log = LoggerFactory.getLogger(RedisUtils.class); + private RedisTemplate redisTemplate; + @Value("${jwt.online-key}") + private String onlineKey; + + public static String LOGIN_FAIL_COUNT = "LOGIN_FAIL_COUNT:%s"; + public static String BLOCKED_ACCOUNT = "BLOCKED_ACCOUNT:%s"; + + public RedisUtils(RedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + /** + * 指定缓存失效时间 + * + * @param key 键 + * @param time 时间(秒) + */ + public boolean expire(String key, long time) { + try { + if (time > 0) { + redisTemplate.expire(key, time, TimeUnit.SECONDS); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + return true; + } + + /** + * 指定缓存失效时间 + * + * @param key 键 + * @param time 时间(秒) + * @param timeUnit 单位 + */ + public boolean expire(String key, long time, TimeUnit timeUnit) { + try { + if (time > 0) { + redisTemplate.expire(key, time, timeUnit); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + return true; + } + + /** + * 根据 key 获取过期时间 + * + * @param key 键 不能为null + * @return 时间(秒) 返回0代表为永久有效 + */ + public long getExpire(Object key) { + return redisTemplate.getExpire(key, TimeUnit.SECONDS); + } + + /** + * 查找匹配key + * + * @param pattern key + * @return / + */ + public List scan(String pattern) { + ScanOptions options = ScanOptions.scanOptions().match(pattern).build(); + RedisConnectionFactory factory = redisTemplate.getConnectionFactory(); + RedisConnection rc = Objects.requireNonNull(factory).getConnection(); + Cursor cursor = rc.scan(options); + List result = new ArrayList<>(); + while (cursor.hasNext()) { + result.add(new String(cursor.next())); + } + try { + RedisConnectionUtils.releaseConnection(rc, factory); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return result; + } + + /** + * 分页查询 key + * + * @param patternKey key + * @param page 页码 + * @param size 每页数目 + * @return / + */ + public List findKeysForPage(String patternKey, int page, int size) { + ScanOptions options = ScanOptions.scanOptions().match(patternKey).build(); + RedisConnectionFactory factory = redisTemplate.getConnectionFactory(); + RedisConnection rc = Objects.requireNonNull(factory).getConnection(); + Cursor cursor = rc.scan(options); + List result = new ArrayList<>(size); + int tmpIndex = 0; + int fromIndex = page * size; + int toIndex = page * size + size; + while (cursor.hasNext()) { + if (tmpIndex >= fromIndex && tmpIndex < toIndex) { + result.add(new String(cursor.next())); + tmpIndex++; + continue; + } + // 获取到满足条件的数据后,就可以退出了 + if (tmpIndex >= toIndex) { + break; + } + tmpIndex++; + cursor.next(); + } + try { + RedisConnectionUtils.releaseConnection(rc, factory); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return result; + } + + /** + * 判断key是否存在 + * + * @param key 键 + * @return true 存在 false不存在 + */ + public boolean hasKey(String key) { + try { + return redisTemplate.hasKey(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 删除缓存 + * + * @param key 可以传一个值 或多个 + */ + public void del(String... keys) { + if (keys != null && keys.length > 0) { + if (keys.length == 1) { + boolean result = redisTemplate.delete(keys[0]); + log.debug("--------------------------------------------"); + log.debug(new StringBuilder("删除缓存:").append(keys[0]).append(",结果:").append(result).toString()); + log.debug("--------------------------------------------"); + } else { + Set keySet = new HashSet<>(); + for (String key : keys) { + keySet.addAll(redisTemplate.keys(key)); + } + long count = redisTemplate.delete(keySet); + log.debug("--------------------------------------------"); + log.debug("成功删除缓存:" + keySet.toString()); + log.debug("缓存删除数量:" + count + "个"); + log.debug("--------------------------------------------"); + } + } + } + + /** + * setIfAbsent 如果key 不存在则 set value 并返回true + * 否则返回false; + * @param key + * @param value + * @return + */ + public Boolean setIfAbsent(String key, String value) { + + try { + return redisTemplate.opsForValue().setIfAbsent(key, value); + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + // ============================String============================= + + /** + * 普通缓存获取 + * + * @param key 键 + * @return 值 + */ + public Object get(String key) { + return key == null ? null : redisTemplate.opsForValue().get(key); + } + + /** + * 批量获取 + * + * @param keys + * @return + */ + public List multiGet(List keys) { + Object obj = redisTemplate.opsForValue().multiGet(Collections.singleton(keys)); + return null; + } + + /** + * 普通缓存放入 + * + * @param key 键 + * @param value 值 + * @return true成功 false失败 + */ + public boolean set(String key, Object value) { + try { + redisTemplate.opsForValue().set(key, value); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 普通缓存放入并设置时间 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 + * @return true成功 false 失败 + */ + public boolean set(String key, Object value, long time) { + try { + if (time > 0) { + redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); + } else { + set(key, value); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 普通缓存放入并设置时间 + * + * @param key 键 + * @param value 值 + * @param time 时间 + * @param timeUnit 类型 + * @return true成功 false 失败 + */ + public boolean set(String key, Object value, long time, TimeUnit timeUnit) { + try { + if (time > 0) { + redisTemplate.opsForValue().set(key, value, time, timeUnit); + } else { + set(key, value); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + // ================================Map================================= + + /** + * HashGet + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return 值 + */ + public Object hget(String key, String item) { + return redisTemplate.opsForHash().get(key, item); + } + + /** + * 获取hashKey对应的所有键值 + * + * @param key 键 + * @return 对应的多个键值 + */ + public Map hmget(String key) { + return redisTemplate.opsForHash().entries(key); + + } + + /** + * HashSet + * + * @param key 键 + * @param map 对应多个键值 + * @return true 成功 false 失败 + */ + public boolean hmset(String key, Map map) { + try { + redisTemplate.opsForHash().putAll(key, map); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * HashSet 并设置时间 + * + * @param key 键 + * @param map 对应多个键值 + * @param time 时间(秒) + * @return true成功 false失败 + */ + public boolean hmset(String key, Map map, long time) { + try { + redisTemplate.opsForHash().putAll(key, map); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value) { + try { + redisTemplate.opsForHash().put(key, item, value); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value, long time) { + try { + redisTemplate.opsForHash().put(key, item, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 删除hash表中的值 + * + * @param key 键 不能为null + * @param item 项 可以使多个 不能为null + */ + public void hdel(String key, Object... item) { + redisTemplate.opsForHash().delete(key, item); + } + + /** + * 判断hash表中是否有该项的值 + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return true 存在 false不存在 + */ + public boolean hHasKey(String key, String item) { + return redisTemplate.opsForHash().hasKey(key, item); + } + + /** + * hash递增 如果不存在,就会创建一个 并把新增后的值返回 + * + * @param key 键 + * @param item 项 + * @param by 要增加几(大于0) + * @return + */ + public double hincr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, by); + } + + /** + * 自增 + * @param key + * @param liveTime 单位秒 + * @return + */ + public Long incrAndExpire(String key, long liveTime) { + RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory()); + Long increment = entityIdCounter.getAndIncrement(); + + if ((null == increment || increment.longValue() == 0) && liveTime > 0) {//初始设置过期时间 + entityIdCounter.expire(liveTime, TimeUnit.SECONDS); + } + + return Long.valueOf(StrUtil.toString(get(key))); + } + + /** + * hash递减 + * + * @param key 键 + * @param item 项 + * @param by 要减少记(小于0) + * @return + */ + public double hdecr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, -by); + } + + // ============================set============================= + + /** + * 根据key获取Set中的所有值 + * + * @param key 键 + * @return + */ + public Set sGet(String key) { + try { + return redisTemplate.opsForSet().members(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; + } + } + + /** + * 随机返回并删除名称为key的set中的一个元素 + * + * @param key 键 + * @return + */ + public ZSetOperations.TypedTuple randomObj(String key) { + try { + Long xxx = redisTemplate.opsForZSet().size(key); + if (ObjectUtil.isEmpty(xxx)) { + return null; + } + Set> allSet = redisTemplate.opsForZSet().rangeWithScores(key,0,-1); + // 随机数 + int leng = allSet.size(); + Random r = new Random(); + Integer arrayindex = r.nextInt(leng); + List> results = new ArrayList<>(allSet); + ZSetOperations.TypedTuple randomObj = results.get(arrayindex); + return randomObj; + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; + } + } + + /** + * 根据value从一个set中查询,是否存在 + * + * @param key 键 + * @param value 值 + * @return true 存在 false不存在 + */ + public boolean sHasKey(String key, Object value) { + try { + return redisTemplate.opsForSet().isMember(key, value); + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 将数据放入set缓存 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSet(String key, Object... values) { + try { + return redisTemplate.opsForSet().add(key, values); + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } + + /** + * 将set数据放入缓存 + * + * @param key 键 + * @param time 时间(秒) + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSetAndTime(String key, long time, Object... values) { + try { + Long count = redisTemplate.opsForSet().add(key, values); + if (time > 0) { + expire(key, time); + } + return count; + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } + + /** + * 获取set缓存的长度 + * + * @param key 键 + * @return + */ + public long sGetSetSize(String key) { + try { + return redisTemplate.opsForSet().size(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } + + /** + * 移除值为value的 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 移除的个数 + */ + public long setRemove(String key, Object... values) { + try { + Long count = redisTemplate.opsForSet().remove(key, values); + return count; + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } + + // ===============================list================================= + + /** + * 获取list缓存的内容 + * + * @param key 键 + * @param start 开始 + * @param end 结束 0 到 -1代表所有值 + * @return + */ + public List lGet(String key, long start, long end) { + try { + return redisTemplate.opsForList().range(key, start, end); + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; + } + } + + /** + * rpop + * + * @param key 键 + * @return + */ + public Object rPop(String key) { + try { + return redisTemplate.opsForList().rightPop(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; + } + } + + /** + * rpop + * + * @param key 键 + * @return + */ + public Object lPop(String key) { + try { + return redisTemplate.opsForList().leftPop(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; + } + } + + /** + * rightPush + * + * @param key 键 + * @return + */ + public Object rPush(String key, Object object) { + try { + return redisTemplate.opsForList().rightPush(key, object); + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; + } + } + + /** + * lPush + * + * @param key 键 + * @return + */ + public Object lPush(String key, Object object) { + try { + return redisTemplate.opsForList().leftPush(key, object); + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; + } + } + + /** + * 获取list缓存的长度 + * + * @param key 键 + * @return + */ + public long lGetListSize(String key) { + try { + return redisTemplate.opsForList().size(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } + + /** + * 通过索引 获取list中的值 + * + * @param key 键 + * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 + * @return + */ + public Object lGetIndex(String key, long index) { + try { + return redisTemplate.opsForList().index(key, index); + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @return + */ + public boolean lSet(String key, Object value) { + try { + redisTemplate.opsForList().leftPush(key, value); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, Object value, long time) { + try { + redisTemplate.opsForList().rightPush(key, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 将String放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean put(String key, Object value, long time) { + try { + redisTemplate.opsForValue().set(key, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @return + */ + public boolean lSet(String key, List value) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, List value, long time) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 根据索引修改list中的某条数据 + * + * @param key 键 + * @param index 索引 + * @param value 值 + * @return / + */ + public boolean lUpdateIndex(String key, long index, Object value) { + try { + redisTemplate.opsForList().set(key, index, value); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 移除N个值为value + * + * @param key 键 + * @param count 移除多少个 + * @param value 值 + * @return 移除的个数 + */ + public long lRemove(String key, long count, Object value) { + try { + return redisTemplate.opsForList().remove(key, count, value); + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } + + /** + * @param prefix 前缀 + * @param ids id + */ + public void delByKeys(String prefix, Set ids) { + Set keys = new HashSet<>(); + for (Long id : ids) { + keys.addAll(redisTemplate.keys(new StringBuffer(prefix).append(id).toString())); + } + long count = redisTemplate.delete(keys); + // 此处提示可自行删除 + log.debug("--------------------------------------------"); + log.debug("成功删除缓存:" + keys.toString()); + log.debug("缓存删除数量:" + count + "个"); + log.debug("--------------------------------------------"); + } + + // ===============================setsort================================= + + /** + * 添加元素到变量中同时指定元素的分值。 + * @param key + * @param value + * @param score + * @return + */ + public boolean zSortAdd(String key, Object value, double score) { + try { + redisTemplate.opsForZSet().add(key, value, score); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 根据分值移除区间元素。 + * @param key + * @param min + * @param max + * @return + */ + public Long removeRangeByScore(String key, double min, double max) { + return redisTemplate.opsForZSet().removeRangeByScore(key, min, max); + } + + /** + * 获取变量指定区间的元素。 + * @param key + * @param start + * @param end + * @return + */ + public Set range(String key, long start, long end) { + return redisTemplate.opsForZSet().range(key, start, end); + } + + /** + * 返回有序集 key 中,成员 member 的 score 值。 + * 如果 member 元素不是有序集 key 的成员,或 key 不存在,返回 nil 。 + * @param key + * @param member + * @return + */ + public Double zscore(String key, Object member) { + return redisTemplate.opsForZSet().score(key, member); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/RedissonUtil.java b/wjcy-common/src/main/java/me/zhengjie/utils/RedissonUtil.java new file mode 100644 index 0000000..f02ed00 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/RedissonUtil.java @@ -0,0 +1,167 @@ +package me.zhengjie.utils; + + +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.exception.BadRequestException; +import org.redisson.api.*; +import org.redisson.config.Config; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +/** + *

+ * redisson + *

+ * + * @Author xx + * @Date 2021/8/11 + **/ +@Slf4j +@Component("redissonUtil") +public class RedissonUtil { + + @Resource + private RedissonClient redissonClient; + + public void getRedissonClient() throws IOException { + Config config = redissonClient.getConfig(); +// System.out.println(config.toJSON().toString()); + } + + /**` + * 获取字符串对象 + * + * @param objectName + * @return + */ + public RBucket getRBucket(String objectName) { + RBucket bucket = redissonClient.getBucket(objectName); + return bucket; + } + + /** + * 获取Map对象 + * + * @param objectName + * @return + */ + public RMap getRMap(String objectName) { + RMap map = redissonClient.getMap(objectName); + return map; + } + + /** + * 获取有序集合 + * + * @param objectName + * @return + */ + public RSortedSet getRSortedSet(String objectName) { + RSortedSet sortedSet = redissonClient.getSortedSet(objectName); + return sortedSet; + } + + /** + * 获取集合 + * + * @param objectName + * @return + */ + public RSet getRSet(String objectName) { + RSet rSet = redissonClient.getSet(objectName); + return rSet; + } + + /** + * 获取列表 + * + * @param objectName + * @return + */ + public RList getRList(String objectName) { + RList rList = redissonClient.getList(objectName); + return rList; + } + + /** + * 获取队列 + * + * @param objectName + * @return + */ + public RQueue getRQueue(String objectName) { + RQueue rQueue = redissonClient.getQueue(objectName); + return rQueue; + } + + /** + * 获取双端队列 + * + * @param objectName + * @return + */ + public RDeque getRDeque(String objectName) { + RDeque rDeque = redissonClient.getDeque(objectName); + return rDeque; + } + + + /** + * 获取锁 + * + * @param objectName + * @return + */ + public RLock getRLock(String objectName) { + RLock rLock = redissonClient.getLock(objectName); + return rLock; + } + + /** + * 获取读取锁 + * + * @param objectName + * @return + */ + public RReadWriteLock getRWLock(String objectName) { + RReadWriteLock rwlock = redissonClient.getReadWriteLock(objectName); + return rwlock; + } + + /** + * 获取原子数 + * + * @param objectName + * @return + */ + public RAtomicLong getRAtomicLong(String objectName) { + RAtomicLong rAtomicLong = redissonClient.getAtomicLong(objectName); + return rAtomicLong; + } + + /** + * 获取记数锁 + * + * @param objectName + * @return + */ + public RCountDownLatch getRCountDownLatch(String objectName) { + RCountDownLatch rCountDownLatch = redissonClient.getCountDownLatch(objectName); + return rCountDownLatch; + } + + /** + * 获取消息的Topic + * + * @param objectName + * @return + */ + public RTopic getRTopic(String objectName) { + RTopic rTopic = redissonClient.getTopic(objectName); + return rTopic; + } +} + diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/RequestHolder.java b/wjcy-common/src/main/java/me/zhengjie/utils/RequestHolder.java new file mode 100644 index 0000000..2720ae5 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/RequestHolder.java @@ -0,0 +1,50 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import me.zhengjie.enums.LanguageEnum; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import javax.servlet.http.HttpServletRequest; +import java.util.Objects; + +/** + * 获取 HttpServletRequest + * @author Zheng Jie + * @date 2018-11-24 + */ +public class RequestHolder { + + public static HttpServletRequest getHttpServletRequest() { + return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest(); + } + + public static String getLanguage() { + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + if (ObjectUtil.isNull(requestAttributes) || !(requestAttributes instanceof ServletRequestAttributes)) { + return LanguageEnum.ZH.getValue(); + } + HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); + if (ObjectUtil.isNull(request)) { + return LanguageEnum.ZH.getValue(); + } + return Convert.toStr(request.getHeader("language"), LanguageEnum.ZH.getValue()); + } + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/RsaUtils.java b/wjcy-common/src/main/java/me/zhengjie/utils/RsaUtils.java new file mode 100644 index 0000000..b42cec7 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/RsaUtils.java @@ -0,0 +1,202 @@ +package me.zhengjie.utils; + +import org.apache.commons.codec.binary.Base64; +import javax.crypto.Cipher; +import java.io.ByteArrayOutputStream; +import java.security.*; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +/** + * @author https://www.cnblogs.com/nihaorz/p/10690643.html + * @description Rsa 工具类,公钥私钥生成,加解密 + * @date 2020-05-18 + **/ +public class RsaUtils { + + private static final String SRC = "panpan@123"; + + public static void main(String[] args) throws Exception { +// System.out.println("\n"); +// RsaKeyPair keyPair = generateKeyPair(); +// System.out.println("公钥:" + keyPair.getPublicKey()); +// System.out.println("私钥:" + keyPair.getPrivateKey()); +// System.out.println("\n"); +// test1(keyPair); +// System.out.println("\n"); +// test2(keyPair); +// System.out.println("\n"); + + + String text1 = encryptByPublicKey("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdFXJjqlBdh1ri8hS2bEvwjREJyRAqruwtf+c/bgFiBOxuW4LAVIiMnimfnmLiL0/h0Q1YLKjrnFkOwXLvZTgwwCiX1uF5WhOyCsGEEQDhfvFTlInemFNdi8zqWxoONbRBb9wJbqS8K6LtzXu2Oltu5hzqQXKwY+sNCVbKCrt/KwIDAQAB", RsaUtils.SRC); + System.out.println(text1); + } + + /** + * 公钥加密私钥解密 + */ + private static void test1(RsaKeyPair keyPair) throws Exception { + System.out.println("***************** 公钥加密私钥解密开始 *****************"); + String text1 = encryptByPublicKey(keyPair.getPublicKey(), RsaUtils.SRC); + String text2 = decryptByPrivateKey(keyPair.getPrivateKey(), text1); + System.out.println("加密前:" + RsaUtils.SRC); + System.out.println("加密后:" + text1); + System.out.println("解密后:" + text2); + if (RsaUtils.SRC.equals(text2)) { + System.out.println("解密字符串和原始字符串一致,解密成功"); + } else { + System.out.println("解密字符串和原始字符串不一致,解密失败"); + } + System.out.println("***************** 公钥加密私钥解密结束 *****************"); + } + + /** + * 私钥加密公钥解密 + * @throws Exception / + */ + private static void test2(RsaKeyPair keyPair) throws Exception { + System.out.println("***************** 私钥加密公钥解密开始 *****************"); + String text1 = encryptByPrivateKey(keyPair.getPrivateKey(), RsaUtils.SRC); + String text2 = decryptByPublicKey(keyPair.getPublicKey(), text1); + System.out.println("加密前:" + RsaUtils.SRC); + System.out.println("加密后:" + text1); + System.out.println("解密后:" + text2); + if (RsaUtils.SRC.equals(text2)) { + System.out.println("解密字符串和原始字符串一致,解密成功"); + } else { + System.out.println("解密字符串和原始字符串不一致,解密失败"); + } + System.out.println("***************** 私钥加密公钥解密结束 *****************"); + } + + /** + * 公钥解密 + * + * @param publicKeyText 公钥 + * @param text 待解密的信息 + * @return / + * @throws Exception / + */ + public static String decryptByPublicKey(String publicKeyText, String text) throws Exception { + X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText)); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.DECRYPT_MODE, publicKey); + byte[] result = doLongerCipherFinal(Cipher.DECRYPT_MODE, cipher, Base64.decodeBase64(text)); + return new String(result); + } + + /** + * 私钥加密 + * + * @param privateKeyText 私钥 + * @param text 待加密的信息 + * @return / + * @throws Exception / + */ + public static String encryptByPrivateKey(String privateKeyText, String text) throws Exception { + PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText)); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, privateKey); + byte[] result = doLongerCipherFinal(Cipher.ENCRYPT_MODE, cipher, text.getBytes()); + return Base64.encodeBase64String(result); + } + + /** + * 私钥解密 + * + * @param privateKeyText 私钥 + * @param text 待解密的文本 + * @return / + * @throws Exception / + */ + public static String decryptByPrivateKey(String privateKeyText, String text) throws Exception { + PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText)); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5); + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + byte[] result = doLongerCipherFinal(Cipher.DECRYPT_MODE, cipher, Base64.decodeBase64(text)); + return new String(result); + } + + /** + * 公钥加密 + * + * @param publicKeyText 公钥 + * @param text 待加密的文本 + * @return / + */ + public static String encryptByPublicKey(String publicKeyText, String text) throws Exception { + X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText)); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2); + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + byte[] result = doLongerCipherFinal(Cipher.ENCRYPT_MODE, cipher, text.getBytes()); + return Base64.encodeBase64String(result); + } + + private static byte[] doLongerCipherFinal(int opMode,Cipher cipher, byte[] source) throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + if (opMode == Cipher.DECRYPT_MODE) { + out.write(cipher.doFinal(source)); + } else { + int offset = 0; + int totalSize = source.length; + while (totalSize - offset > 0) { + int size = Math.min(cipher.getOutputSize(0) - 11, totalSize - offset); + out.write(cipher.doFinal(source, offset, size)); + offset += size; + } + } + out.close(); + return out.toByteArray(); + } + + /** + * 构建RSA密钥对 + * + * @return / + * @throws NoSuchAlgorithmException / + */ + public static RsaKeyPair generateKeyPair() throws NoSuchAlgorithmException { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(1024); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic(); + RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate(); + String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded()); + String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded()); + return new RsaKeyPair(publicKeyString, privateKeyString); + } + + + /** + * RSA密钥对对象 + */ + public static class RsaKeyPair { + + private final String publicKey; + private final String privateKey; + + public RsaKeyPair(String publicKey, String privateKey) { + this.publicKey = publicKey; + this.privateKey = privateKey; + } + + public String getPublicKey() { + return publicKey; + } + + public String getPrivateKey() { + return privateKey; + } + + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/SecurityUtils.java b/wjcy-common/src/main/java/me/zhengjie/utils/SecurityUtils.java new file mode 100644 index 0000000..dfeee43 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/SecurityUtils.java @@ -0,0 +1,109 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils; + +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.utils.enums.DataScopeEnum; +import org.springframework.http.HttpStatus; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import java.util.List; + +/** + * 获取当前登录的用户 + * @author Zheng Jie + * @date 2019-01-17 + */ +@Slf4j +public class SecurityUtils { + + /** + * 获取当前登录的用户 + * @return UserDetails + */ + public static UserDetails getCurrentUser() { + UserDetailsService userDetailsService = SpringContextHolder.getBean(UserDetailsService.class); + return userDetailsService.loadUserByUsername(getCurrentUsername()); + } + + /** + * 获取系统用户名称 + * + * @return 系统用户名称 + */ + public static String getCurrentUsername() { + final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null) { + throw new BadRequestException(HttpStatus.UNAUTHORIZED, "当前登录状态过期"); + } + if (authentication.getPrincipal() instanceof UserDetails) { + UserDetails userDetails = (UserDetails) authentication.getPrincipal(); + return userDetails.getUsername(); + } + throw new BadRequestException(HttpStatus.UNAUTHORIZED, "找不到当前登录的信息"); + } + + /** + * 获取系统用户ID + * @return 系统用户ID + */ + public static Long getCurrentUserId() { + UserDetails userDetails = getCurrentUser(); + return new JSONObject(new JSONObject(userDetails).get("user")).get("id", Long.class); + } + + /** + * 是否是总商户号 + * @return true:是 + */ + public static boolean isAdmin() { + UserDetails userDetails = getCurrentUser(); + return new JSONObject(new JSONObject(userDetails).get("user")).get("isAdmin", Boolean.class); + } + + + public static boolean isNotAdmin() { + return !isAdmin(); + } + + /** + * 获取当前用户的数据权限 + * @return / + */ + public static List getCurrentUserDataScope(){ + UserDetails userDetails = getCurrentUser(); + JSONArray array = JSONUtil.parseArray(new JSONObject(userDetails).get("dataScopes")); + return JSONUtil.toList(array,Long.class); + } + + /** + * 获取数据权限级别 + * @return 级别 + */ + public static String getDataScopeType() { + List dataScopes = getCurrentUserDataScope(); + if(dataScopes.size() != 0){ + return ""; + } + return DataScopeEnum.ALL.getValue(); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/SpringContextHolder.java b/wjcy-common/src/main/java/me/zhengjie/utils/SpringContextHolder.java new file mode 100644 index 0000000..4f3aaf6 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/SpringContextHolder.java @@ -0,0 +1,151 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.core.env.Environment; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @author Jie + * @date 2019-01-07 + */ +@Slf4j +public class SpringContextHolder implements ApplicationContextAware, DisposableBean { + + private static ApplicationContext applicationContext = null; + private static final List CALL_BACKS = new ArrayList<>(); + private static boolean addCallback = true; + + /** + * 针对 某些初始化方法,在SpringContextHolder 未初始化时 提交回调方法。 + * 在SpringContextHolder 初始化后,进行回调使用 + * + * @param callBack 回调函数 + */ + public synchronized static void addCallBacks(CallBack callBack) { + if (addCallback) { + SpringContextHolder.CALL_BACKS.add(callBack); + } else { + log.warn("CallBack:{} 已无法添加!立即执行", callBack.getCallBackName()); + callBack.executor(); + } + } + + /** + * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. + */ + @SuppressWarnings("unchecked") + public static T getBean(String name) { + assertContextInjected(); + return (T) applicationContext.getBean(name); + } + + public static Map getBeansOfType(Class tClass) { + assertContextInjected(); + return applicationContext.getBeansOfType(tClass); + } + + /** + * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. + */ + public static T getBean(Class requiredType) { + assertContextInjected(); + return applicationContext.getBean(requiredType); + } + + /** + * 获取SpringBoot 配置信息 + * + * @param property 属性key + * @param defaultValue 默认值 + * @param requiredType 返回类型 + * @return / + */ + public static T getProperties(String property, T defaultValue, Class requiredType) { + T result = defaultValue; + try { + result = getBean(Environment.class).getProperty(property, requiredType); + } catch (Exception ignored) {} + return result; + } + + /** + * 获取SpringBoot 配置信息 + * + * @param property 属性key + * @return / + */ + public static String getProperties(String property) { + return getProperties(property, null, String.class); + } + + /** + * 获取SpringBoot 配置信息 + * + * @param property 属性key + * @param requiredType 返回类型 + * @return / + */ + public static T getProperties(String property, Class requiredType) { + return getProperties(property, null, requiredType); + } + + /** + * 检查ApplicationContext不为空. + */ + private static void assertContextInjected() { + if (applicationContext == null) { + throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" + + ".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder."); + } + } + + /** + * 清除SpringContextHolder中的ApplicationContext为Null. + */ + private static void clearHolder() { + log.debug("清除SpringContextHolder中的ApplicationContext:" + + applicationContext); + applicationContext = null; + } + + @Override + public void destroy() { + SpringContextHolder.clearHolder(); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + if (SpringContextHolder.applicationContext != null) { + log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext); + } + SpringContextHolder.applicationContext = applicationContext; + if (addCallback) { + for (CallBack callBack : SpringContextHolder.CALL_BACKS) { + callBack.executor(); + } + CALL_BACKS.clear(); + } + SpringContextHolder.addCallback = false; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/StringUtil.java b/wjcy-common/src/main/java/me/zhengjie/utils/StringUtil.java new file mode 100644 index 0000000..c2c474d --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/StringUtil.java @@ -0,0 +1,200 @@ +package me.zhengjie.utils; + + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; + +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.util.Calendar; +import java.util.LinkedList; +import java.util.List; +/** + *

+ * 驼峰与下划线的属性名互相转换 + *

+ * + * @Author xx + * @Date 2021/7/20 + **/ +public class StringUtil { + + /** + * 先按英文逗号打散成字符串数组,在随机从中选择一个返回 + * @author: zeng + */ + public static String spiltAndRandom(String str){ + if (ObjectUtil.isEmpty(str)) { + return null; + } + String[] split = str.split(","); + + int randomNum = (int) (Math.random() * split.length); + return split[randomNum]; + } + + /** + * 验证4段ip地址是否符合规范,并且开始的ip不能大于结束的ip + * + * @return + */ + public static boolean verifyIpAddr(String beginIp, String endIp) { + String[] beginIPsplit = beginIp.split("\\."); + String[] endIPsplit = endIp.split("\\."); + if (beginIPsplit.length == 4 && endIPsplit.length == 4) { + for (int i = 0; i < 4; i++) { + if (Convert.toInt(beginIPsplit[i]) < 0 || Convert.toInt(beginIPsplit[i]) > 255) { + return false; + } + if (Convert.toInt(endIPsplit[i]) < 0 || Convert.toInt(endIPsplit[i]) > 255) { + return false; + } +// if (Convert.toInt(beginIPsplit[i]) > Convert.toInt(endIPsplit[i])) { +// return false; +// } + } + return true; + } + return false; + } + + /** + * 转换为下划线 + * + * @param camelCaseName + * @return + */ + public static String underscoreName(String camelCaseName) { + StringBuilder result = new StringBuilder(); + if (camelCaseName != null && camelCaseName.length() > 0) { + result.append(camelCaseName.substring(0, 1).toLowerCase()); + for (int i = 1; i < camelCaseName.length(); i++) { + char ch = camelCaseName.charAt(i); + if (Character.isUpperCase(ch)) { + result.append("_"); + result.append(Character.toLowerCase(ch)); + } else { + result.append(ch); + } + } + } + return result.toString(); + } + + /** + * 转换为驼峰 + * + * @param underscoreName + * @return + */ + public static String camelCaseName(String underscoreName) { + StringBuilder result = new StringBuilder(); + if (underscoreName != null && underscoreName.length() > 0) { + boolean flag = false; + for (int i = 0; i < underscoreName.length(); i++) { + char ch = underscoreName.charAt(i); + if ("_".charAt(0) == ch) { + flag = true; + } else { + if (flag) { + result.append(Character.toUpperCase(ch)); + flag = false; + } else { + result.append(ch); + } + } + } + } + return result.toString(); + } + + public static String getDeviceType(String userAgent) { + if (ObjectUtil.isNotEmpty(userAgent)) { + + userAgent = userAgent.toUpperCase(); + + if (userAgent.contains("WINDOWS")) { + return "WINDOWS"; + } + if (userAgent.contains("IPHONE")) { + return "IOS"; + } + if (userAgent.contains("HUAWEI")) { + return "华为"; + } + if (userAgent.contains("MI")) { + return "小米"; + } + if (userAgent.contains("VIVO")) { + return "VIVO"; + } + if (userAgent.contains("OPPO")) { + return "OPPO"; + } + if (userAgent.contains("MEIZU")) { + return "魅族"; + } + if (userAgent.contains("SM-")) { + return "三星"; + } + if (userAgent.contains("ANDROID")){ + return "安卓"; + } + } + return "未知"; + } + + //设置时间格式 + static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + + /** + * 获取当月第一天 yyyy-MM-dd 格式日期 + * @return + */ + public static String getMonthFirstDay() { + Calendar ca = Calendar.getInstance(); + ca.add(Calendar.MONTH, 0); + ca.set(Calendar.DAY_OF_MONTH, 1); + String firstDay = format.format(ca.getTime()); + return firstDay; + } + /** + * 获取当月最后一天 yyyy-MM-dd 格式日期 + * @return + */ + public static String getMonthLastDay() { + //获得实体类 + Calendar ca = Calendar.getInstance(); + //设置最后一天 + ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH)); + //最后一天格式化 + String lastDay = format.format(ca.getTime()); + return lastDay; + } + + /** + * 获取当月每天的 yyyy-MM-dd 格式日期 + * @return + */ + public static List getMonthAllDay() { + List list = new LinkedList(); + LocalDate monthFirstDay = DateUtil.parseLocalDateFormatyMd(getMonthFirstDay()); + LocalDate monthLastDay = DateUtil.parseLocalDateFormatyMd(getMonthLastDay()); + while (true) { + list.add(monthFirstDay.toString()); + if (monthFirstDay.equals(monthLastDay)) { + return list; + } + monthFirstDay = monthFirstDay.plusDays(1); + } + } + + + public static void main(String[] args) { + // System.out.println(StringUtil.underscoreName("orderNo")); +// getMonthAllDay().forEach(System.out::println); + + String deviceType = getDeviceType("NX629J(Android/11) (com.hj.bybf8) UniApp/0.28.0 1080x2340"); + System.out.println(deviceType); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/StringUtils.java b/wjcy-common/src/main/java/me/zhengjie/utils/StringUtils.java new file mode 100644 index 0000000..b5c2bd6 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/StringUtils.java @@ -0,0 +1,332 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils; + +import cn.hutool.http.HttpUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import me.zhengjie.config.SystemConfig; +import nl.basjes.parse.useragent.UserAgent; +import nl.basjes.parse.useragent.UserAgentAnalyzer; +import org.lionsoul.ip2region.DataBlock; +import org.lionsoul.ip2region.DbConfig; +import org.lionsoul.ip2region.DbSearcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletRequest; +import java.io.File; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.UnknownHostException; +import java.util.Calendar; +import java.util.Date; +import java.util.Enumeration; + +/** + * @author Zheng Jie + * 字符串工具类, 继承org.apache.commons.lang3.StringUtils类 + */ +public class StringUtils extends org.apache.commons.lang3.StringUtils { + + private static final Logger log = LoggerFactory.getLogger(StringUtils.class); + private static boolean ipLocal = false; + private static File file = null; + private static DbConfig config; + private static final char SEPARATOR = '_'; + private static final String UNKNOWN = "unknown"; + + private static final UserAgentAnalyzer userAgentAnalyzer = UserAgentAnalyzer + .newBuilder() + .hideMatcherLoadStats() + .withCache(10000) + .withField(UserAgent.AGENT_NAME_VERSION) + .build(); + + + static { + SpringContextHolder.addCallBacks(() -> { + StringUtils.ipLocal = SpringContextHolder.getProperties("ip.local-parsing", false, Boolean.class); + if (ipLocal) { + /* + * 此文件为独享 ,不必关闭 + */ +// String path = "ip2region/ip2region.db"; +// String name = "ip2region.db"; + try { + config = new DbConfig(); + file = new File(SystemConfig.IP2REGION_DB_PATH); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + }); + } + + /** + * 驼峰命名法工具 + * + * @return toCamelCase(" hello_world ") == "helloWorld" + * toCapitalizeCamelCase("hello_world") == "HelloWorld" + * toUnderScoreCase("helloWorld") = "hello_world" + */ + public static String toCamelCase(String s) { + if (s == null) { + return null; + } + + s = s.toLowerCase(); + + StringBuilder sb = new StringBuilder(s.length()); + boolean upperCase = false; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + + if (c == SEPARATOR) { + upperCase = true; + } else if (upperCase) { + sb.append(Character.toUpperCase(c)); + upperCase = false; + } else { + sb.append(c); + } + } + + return sb.toString(); + } + + /** + * 驼峰命名法工具 + * + * @return toCamelCase(" hello_world ") == "helloWorld" + * toCapitalizeCamelCase("hello_world") == "HelloWorld" + * toUnderScoreCase("helloWorld") = "hello_world" + */ + public static String toCapitalizeCamelCase(String s) { + if (s == null) { + return null; + } + s = toCamelCase(s); + return s.substring(0, 1).toUpperCase() + s.substring(1); + } + + /** + * 驼峰命名法工具 + * + * @return toCamelCase(" hello_world ") == "helloWorld" + * toCapitalizeCamelCase("hello_world") == "HelloWorld" + * toUnderScoreCase("helloWorld") = "hello_world" + */ + static String toUnderScoreCase(String s) { + if (s == null) { + return null; + } + + StringBuilder sb = new StringBuilder(); + boolean upperCase = false; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + + boolean nextUpperCase = true; + + if (i < (s.length() - 1)) { + nextUpperCase = Character.isUpperCase(s.charAt(i + 1)); + } + + if ((i > 0) && Character.isUpperCase(c)) { + if (!upperCase || !nextUpperCase) { + sb.append(SEPARATOR); + } + upperCase = true; + } else { + upperCase = false; + } + + sb.append(Character.toLowerCase(c)); + } + + return sb.toString(); + } + + /** + * 获取ip地址 + */ + public static String getIp(HttpServletRequest request) { + String ip = request.getHeader("X-Real-IP"); + if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { + ip = request.getHeader("X-Forwarded-For"); + } + if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + String comma = ","; + String localhost = "127.0.0.1"; + if (ip.contains(comma)) { + ip = ip.split(",")[0]; + } + if (localhost.equals(ip)) { + // 获取本机真正的ip地址 + try { + ip = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + log.error(e.getMessage(), e); + } + } + return ip; + } + + /** + * 根据ip获取详细地址 + */ + public static String getCityInfo(String ip) { + if (ipLocal) { + return getLocalCityInfo(ip); + } else { + return getHttpCityInfo(ip); + } + } + + /** + * 根据ip获取详细地址 + */ + public static String getHttpCityInfo(String ip) { + String api = String.format(ElAdminConstant.Url.IP_URL, ip); + JSONObject object = JSONUtil.parseObj(HttpUtil.get(api)); + return object.get("addr", String.class); + } + + /** + * 根据ip获取详细地址 + */ + public static String getLocalCityInfo(String ip) { + try { + DataBlock dataBlock = new DbSearcher(config, file.getPath()) + .binarySearch(ip); + String region = dataBlock.getRegion(); + String address = region.replace("0|", ""); + char symbol = '|'; + if (address.charAt(address.length() - 1) == symbol) { + address = address.substring(0, address.length() - 1); + } + return address.equals(ElAdminConstant.REGION) ? "内网IP" : address; + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return ""; + } + + public static String getBrowser(HttpServletRequest request) { + UserAgent.ImmutableUserAgent userAgent = userAgentAnalyzer.parse(request.getHeader("User-Agent")); + return userAgent.get(UserAgent.AGENT_NAME_VERSION).getValue(); + } + + /** + * 获得当天是周几 + */ + public static String getWeekDay() { + String[] weekDays = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + + int w = cal.get(Calendar.DAY_OF_WEEK) - 1; + if (w < 0) { + w = 0; + } + return weekDays[w]; + } + + /** + * 获取当前机器的IP + * + * @return / + */ + public static String getLocalIp() { + try { + InetAddress candidateAddress = null; + // 遍历所有的网络接口 + for (Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); interfaces.hasMoreElements();) { + NetworkInterface anInterface = interfaces.nextElement(); + // 在所有的接口下再遍历IP + for (Enumeration inetAddresses = anInterface.getInetAddresses(); inetAddresses.hasMoreElements();) { + InetAddress inetAddr = inetAddresses.nextElement(); + // 排除loopback类型地址 + if (!inetAddr.isLoopbackAddress()) { + if (inetAddr.isSiteLocalAddress()) { + // 如果是site-local地址,就是它了 + return inetAddr.getHostAddress(); + } else if (candidateAddress == null) { + // site-local类型的地址未被发现,先记录候选地址 + candidateAddress = inetAddr; + } + } + } + } + if (candidateAddress != null) { + return candidateAddress.getHostAddress(); + } + // 如果没有发现 non-loopback地址.只能用最次选的方案 + InetAddress jdkSuppliedAddress = InetAddress.getLocalHost(); + if (jdkSuppliedAddress == null) { + return ""; + } + return jdkSuppliedAddress.getHostAddress(); + } catch (Exception e) { + return ""; + } + } + + public static String append(String str, char appendValue, int count) { + + StringBuilder stringBuilder = new StringBuilder(str); + for (int i = 0; i < count; i++) { + stringBuilder.append(appendValue); + } + + return stringBuilder.toString(); + } + + + /** + * 首字母大写 + * + * @param string + * @return + */ + public static String toUpperCase4Index(String string) { + char[] methodName = string.toCharArray(); + methodName[0] = toUpperCase(methodName[0]); + return String.valueOf(methodName); + } + + /** + * 字符转成大写 + * + * @param chars + * @return + */ + public static char toUpperCase(char chars) { + if (97 <= chars && chars <= 122) { + chars ^= 32; + } + return chars; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/ThrowableUtil.java b/wjcy-common/src/main/java/me/zhengjie/utils/ThrowableUtil.java new file mode 100644 index 0000000..075a65c --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/ThrowableUtil.java @@ -0,0 +1,37 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * 异常工具 2019-01-06 + * @author Zheng Jie + */ +public class ThrowableUtil { + + /** + * 获取堆栈信息 + */ + public static String getStackTrace(Throwable throwable){ + StringWriter sw = new StringWriter(); + try (PrintWriter pw = new PrintWriter(sw)) { + throwable.printStackTrace(pw); + return sw.toString(); + } + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/TransformMap.java b/wjcy-common/src/main/java/me/zhengjie/utils/TransformMap.java new file mode 100644 index 0000000..c5aa2be --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/TransformMap.java @@ -0,0 +1,60 @@ +package me.zhengjie.utils; + + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; + +import java.util.Collections; +import java.util.Map; +/** + *

+ * DTO 转为 map集合,并过滤时间 + *

+ * + * @Author xx + * @Date 2021/7/22 + **/ +public class TransformMap { + + public static Map toMap(Object dto) { + if (dto == null) { + return Collections.emptyMap(); + } + Object obj = EmptyAttributeFiler.emptyAttributeFiler(dto); + Map map = BeanUtil.beanToMap(obj); + if (obj instanceof Map) { + map = (Map)obj; + } + String stime = Convert.toStr(map.get("stime")); + String etime = Convert.toStr(map.get("etime")); + if (ObjectUtil.isAllNotEmpty(stime,etime) && (stime.length()== etime.length() && stime.length()==10)) { + map.put("stime", map.get("stime").toString() + " 00:00:00"); + map.put("etime", map.get("etime").toString() + " 23:59:59"); + } + Integer page = Convert.toInt(map.get("page")); + Integer pageSize = Convert.toInt(map.get("pageSize")); + if (ObjectUtil.isNotNull(page) && ObjectUtil.isNotNull(pageSize)) { + if (page < 1) { + page = 1; + } + if (pageSize < 1) { + pageSize = 10; + map.put("pageSize", 10); + } + map.put("page", (page - 1) * pageSize); + } + Double minPrice =Convert.toDouble(map.get("minPrice")); + if(ObjectUtil.isNotNull(minPrice)){ + map.put("minPrice",minPrice*100); + } + + Double maxPrice =Convert.toDouble(map.get("maxPrice")); + if(ObjectUtil.isNotNull(maxPrice)){ + map.put("maxPrice",maxPrice*100); + } + return map; + } + + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/TransformQueryWrapper.java b/wjcy-common/src/main/java/me/zhengjie/utils/TransformQueryWrapper.java new file mode 100644 index 0000000..f796fd0 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/TransformQueryWrapper.java @@ -0,0 +1,165 @@ +package me.zhengjie.utils; + + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import me.zhengjie.entity.QueryWrapperAndPage; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Date; +import java.util.Map; +/** + *

+ * DTO 转为 QueryWrapper,并过滤时间 + *

+ * + * @Author xx + * @Date 2021/7/20 + **/ +public class TransformQueryWrapper { + + /** + * DTO 转QueryWrapperAndPage + * 时间特殊处理 其他都是等于 + * 参数对象 属性命名 保持与书库驼峰对应 + * @param dto + * @return + */ + public QueryWrapperAndPage dtoToQueryWrapper(Object dto) { + QueryWrapperAndPage queryWrapperAndPage = new QueryWrapperAndPage(); + QueryWrapper queryWrapper = new QueryWrapper<>(); + Page page = new Page<>(1,10); + Map dtoMap = BeanUtil.beanToMap(dto); + if (ObjectUtil.isNotNull(dtoMap.get("stime"))) { + queryWrapper.ge("created_at", dtoMap.get("stime").toString() + " 00:00:00"); + dtoMap.remove("stime"); + } + + if (ObjectUtil.isNotNull(dtoMap.get("etime"))) { + queryWrapper.le("created_at", dtoMap.get("etime").toString() + " 23:59:59"); + dtoMap.remove("etime"); + } + if (ObjectUtil.isNotNull(dtoMap.get("guessStime"))) { + queryWrapper.ge("completion_time", dtoMap.get("guessStime").toString() + " 00:00:00"); + dtoMap.remove("guessStime"); + } + + if (ObjectUtil.isNotNull(dtoMap.get("guessEtime"))) { + queryWrapper.le("completion_time", dtoMap.get("guessEtime").toString() + " 23:59:59"); + dtoMap.remove("guessEtime"); + } + if (ObjectUtil.isNotNull(dtoMap.get("gamestime"))) { + queryWrapper.ge("start_time", dtoMap.get("gamestime").toString() + " 00:00:00"); + dtoMap.remove("gamestime"); + } + + if (ObjectUtil.isNotNull(dtoMap.get("gameetime"))) { + queryWrapper.le("start_time", dtoMap.get("gameetime").toString() + " 23:59:59"); + dtoMap.remove("gameetime"); + } + + if (ObjectUtil.isNotNull(dtoMap.get("releaseStime"))) { + queryWrapper.ge("release_time", dtoMap.get("releaseStime").toString() + " 00:00:00"); + dtoMap.remove("releaseStime"); + } + + if (ObjectUtil.isNotNull(dtoMap.get("releaseEtime"))) { + queryWrapper.le("release_time", dtoMap.get("releaseEtime").toString() + " 23:59:59"); + dtoMap.remove("releaseEtime"); + } + // 封装所有分页信息 + if (ObjectUtil.isNotEmpty(dtoMap.get("page")) && ObjectUtil.isNotEmpty(dtoMap.get("pageSize"))) { + page.setCurrent(Long.valueOf(dtoMap.get("page").toString())); + page.setSize(Long.valueOf(dtoMap.get("pageSize").toString())); + queryWrapperAndPage.setPage(page); + dtoMap.remove("page"); + dtoMap.remove("pageSize"); + } + + // 封装所有查询条件信息 + for (Map.Entry map :dtoMap.entrySet()) { + if (ObjectUtil.isNotEmpty(map.getValue())){ + queryWrapper.eq(StringUtil.underscoreName(map.getKey()), map.getValue()); + } + } + + queryWrapperAndPage.setQueryWrapper(queryWrapper); + + return queryWrapperAndPage; + } + + /** + * 目前都是等值赋值。 需要的话在后续拓展 + * @param model + * @return + */ + public static QueryWrapper toQueryWrapper(Object model) { + + QueryWrapper queryWrapper = new QueryWrapper<>(); + + // 通过反射 赋值 + Field[] field = model.getClass().getDeclaredFields(); + try { + // 遍历所有属性 + for (int j = 0; j < field.length; j++) { + // 获取属性的名字 + String name = field[j].getName(); + // 将属性的首字符大写,方便构造get,set方法 + name = name.substring(0, 1).toUpperCase() + name.substring(1); + // 获取属性的类型 + String type = field[j].getGenericType().toString(); + // 如果type是类类型,则前面包含"class ",后面跟类名 + if ("class java.lang.String".equals(type)) { + Method m = model.getClass().getMethod("get" + name); + // 调用getter方法获取属性值 + String value = (String) m.invoke(model); + if (ObjectUtil.isNotEmpty(value)) { + queryWrapper.eq(name, value); + } + } + if ("class java.lang.Integer".equals(type)) { + Method m = model.getClass().getMethod("get" + name); + Integer value = (Integer) m.invoke(model); + + if (ObjectUtil.isNotEmpty(value)){ + queryWrapper.eq(name, value); + } + } + if ("class java.lang.Boolean".equals(type)) { + Method m = model.getClass().getMethod("get" + name); + Boolean value = (Boolean) m.invoke(model); + + if (ObjectUtil.isNotEmpty(value)){ + queryWrapper.eq(name, value); + } + } + if ("class java.util.Date".equals(type)) { + Method m = model.getClass().getMethod("get" + name); + Date value = (Date) m.invoke(model); + + if (ObjectUtil.isNotEmpty(value)){ + queryWrapper.eq(name, value); + } + } + + // 如果有需要,可以仿照上面继续进行扩充,再增加对其它类型的判断 + } + }catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (SecurityException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + + return queryWrapper; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/TranslatorUtil.java b/wjcy-common/src/main/java/me/zhengjie/utils/TranslatorUtil.java new file mode 100644 index 0000000..f2bd5d2 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/TranslatorUtil.java @@ -0,0 +1,66 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils; + +import cn.hutool.json.JSONArray; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; + +/** + * @author Zheng Jie + * 翻译工具类 + */ +public class TranslatorUtil { + + public static String translate(String word){ + try { + String url = "https://translate.googleapis.com/translate_a/single?" + + "client=gtx&" + + "sl=en" + + "&tl=zh-CN" + + "&dt=t&q=" + URLEncoder.encode(word, "UTF-8"); + + URL obj = new URL(url); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + con.setRequestProperty("User-Agent", "Mozilla/5.0"); + + BufferedReader in = new BufferedReader( + new InputStreamReader(con.getInputStream())); + String inputLine; + StringBuilder response = new StringBuilder(); + + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + return parseResult(response.toString()); + }catch (Exception e){ + return word; + } + } + + private static String parseResult(String inputJson){ + JSONArray jsonArray2 = (JSONArray) new JSONArray(inputJson).get(0); + StringBuilder result = new StringBuilder(); + for (Object o : jsonArray2) { + result.append(((JSONArray) o).get(0).toString()); + } + return result.toString(); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/ValidationUtil.java b/wjcy-common/src/main/java/me/zhengjie/utils/ValidationUtil.java new file mode 100644 index 0000000..c2c81d2 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/ValidationUtil.java @@ -0,0 +1,126 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils; + +import cn.hutool.core.util.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.exception.BadRequestException; +import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator; + +import java.lang.reflect.Field; + +/** + * 验证工具 + * @author Zheng Jie + * @date 2018-11-23 + */ +@Slf4j +public class ValidationUtil{ + + /** + * 验证空 + */ + public static void isNull(Object obj, String entity, String parameter , Object value){ + if(ObjectUtil.isNull(obj)){ + String msg = entity + " 不存在: "+ parameter +" is "+ value; + throw new BadRequestException(msg); + } + } + + /** + * 验证是否为邮箱 + */ + public static boolean isEmail(String email) { + return new EmailValidator().isValid(email, null); + } + + + /** + * 反射检验对象是否包含指定名称的 变量 + * @param fieldName + * @param obj + * @return + */ + public static Boolean isExistFieldName(String fieldName, Object obj) { + if (obj == null || StringUtils.isEmpty(fieldName)) { + return false; + } + //获取这个类的所有属性 + Field[] fields = obj.getClass().getDeclaredFields(); + //循环遍历所有的fields + for (int i = 0; i < fields.length; i++) { + if (fields[i].getName().equals(fieldName)) { + return true; + } + } + return false; + } + +// /** +// * 判断是否包含 passType +// * @param mqSettlePassCurrencyTypeList +// * @param passType +// * @return +// */ +// public static Boolean isContainPassType(List mqSettlePassCurrencyTypeList, Integer passType) { +// if (ObjectUtil.isEmpty(mqSettlePassCurrencyTypeList) || ObjectUtil.isEmpty(passType)) { +// log.error("---isContainPassType------mqSettlePassCurrencyTypeList-------null"); +// return false; +// } +// List list = mqSettlePassCurrencyTypeList.stream().filter(l->l.getPassType().equals(passType)).collect(Collectors.toList()); +// if (ObjectUtil.isNotEmpty(list)) { +// return true; +// } +// +// log.error("---isContainPassType------mqSettlePassCurrencyTypeList----return---null"); +// return false; +// } +// +// /** +// * 判断是否包含 passType 中的currencyType +// * @param mqSettlePassCurrencyTypeList +// * @param passType +// * @param currencyType +// * @return +// */ +// public static Boolean isContainPassCurrencyType(List mqSettlePassCurrencyTypeList, Integer passType, Integer currencyType) { +// if (ObjectUtil.isEmpty(mqSettlePassCurrencyTypeList) || ObjectUtil.isEmpty(passType) || ObjectUtil.isEmpty(currencyType)) { +// log.error("---isContainPassCurrencyType------mqSettlePassCurrencyTypeList-------null"); +// return false; +// } +// +// List list = mqSettlePassCurrencyTypeList.stream().filter(l->l.getPassType().equals(passType)).collect(Collectors.toList()); +// if (ObjectUtil.isEmpty(list)) { +// log.error("---isContainPassCurrencyType------List----return---false"); +// return false; +// } +// +// for (MqSettlePassCurrencyType mqSettlePassCurrencyType:list) { +// List currencyTypeList = mqSettlePassCurrencyType.getCurrencyList(); +// if (ObjectUtil.isEmpty(currencyTypeList)) { +// continue; +// } +// +// List currencyList = currencyTypeList.stream().filter(c->c.getCurrencyType().equals(currencyType)).collect(Collectors.toList()); +// if (ObjectUtil.isNotEmpty(currencyList)) { +// return true; +// } +// } +// +// log.error("---isContainPassCurrencyType------mqSettlePassCurrencyTypeList----return---false"); +// return false; +// } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/YdCallBackUtil.java b/wjcy-common/src/main/java/me/zhengjie/utils/YdCallBackUtil.java new file mode 100644 index 0000000..6a6b29f --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/YdCallBackUtil.java @@ -0,0 +1,89 @@ +package me.zhengjie.utils; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.config.BeanFactory; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.CtApply; +import me.zhengjie.entity.CtRebot; +import me.zhengjie.entity.ReturnObje; +import me.zhengjie.entity.YdSign; +import me.zhengjie.enums.YesOrNoEnum; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.service.CtRebotService; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * 影刀回调 + * + * @author rch + * @create 2022-08-23 + */ +@Slf4j +public class YdCallBackUtil { + + @Transactional(rollbackFor = Exception.class) + public Dto callback(HttpServletRequest httpServletRequest, CtApply ctApply, String data){ + log.info("=======影刀回调=======callback"); + String requestUrl = httpServletRequest.getRequestURI(); + Map map = httpServletRequest.getParameterMap(); + if (ObjectUtil.isEmpty(map.get("sign"))) { + return Dto.getInstance(ErrorCodeEnum.ERROR_PARAM_NULL); + } + + String getSign = map.get("sign")[0]; + JSONObject jsonObject = JSONUtil.parseObj(data); + + // 根据task枚举获取 应用信息 取出 accessKey 和 accessKeySecret 用于鉴权 + if (ObjectUtil.isEmpty(ctApply) || ObjectUtil.isEmpty(getSign) + || ObjectUtil.isEmpty(jsonObject) + || ObjectUtil.isEmpty(ctApply.getAccessKeyId()) + || ObjectUtil.isEmpty(ctApply.getAccessKeySecret())) { + return Dto.getInstance(ErrorCodeEnum.ERROR_PARAM_NULL); + } + + String accessKeyId = ctApply.getAccessKeyId(); + String accessKeySecret = ctApply.getAccessKeySecret(); + + // 鉴权 + YdSign ydSign = new YdSign(); + ydSign.setTimestamp(Long.valueOf(map.get("timestamp")[0])); + ydSign.setAccessKeyId(accessKeyId); + ydSign.setAccessKeySecret(accessKeySecret); + ydSign.setBodyMd5(map.get("bodyMd5")[0]); + + log.info("-------map:{}" , JSONUtil.toJsonStr(map)); + log.info("====ydSign====={}", JSONUtil.toJsonStr(ydSign)); + String sign = YdSignUtil.getSign(ydSign); + log.info("====sign:{} ---getSign:{}", sign, getSign); + if (ObjectUtil.isEmpty(sign) || !getSign.equals(sign)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_CALLBACK_SIGN_NULL); + } + + // TODO 获取设备id 然后修改设备状态是未占用 + CtRebotService ctRebotService = BeanFactory.getBean(CtRebotService.class); + ReturnObje returnObje = JSONUtil.toBean(data, ReturnObje.class); + String rebotClientName = returnObje.getRobotClientName(); + CtRebot ctRebot = ctRebotService.getByAccountNameLock(rebotClientName); + if (ObjectUtil.isEmpty(ctRebot)) { + // 有问题 不执行 + System.out.println("===========设备有问题==========="); + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_OR_OCCUPY); + } + if (YesOrNoEnum.NO.eqValue(ctRebot.getStatus())) { + return Dto.returnResult(true); + } + + // 修改机器人状态 不管是什么状态,执行完成之后在我们平台就是修改为 待占用即可 + CtRebot updateCtRebot = new CtRebot(); + updateCtRebot.setId(ctRebot.getId()); + updateCtRebot.setStatus(YesOrNoEnum.NO.value()); + Boolean resultBoolean = ctRebotService.updateById(updateCtRebot); + return Dto.returnResult(resultBoolean); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/YdParamsCheck.java b/wjcy-common/src/main/java/me/zhengjie/utils/YdParamsCheck.java new file mode 100644 index 0000000..b69eea3 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/YdParamsCheck.java @@ -0,0 +1,54 @@ +package me.zhengjie.utils; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import me.zhengjie.entity.quartz.Boss; +import me.zhengjie.entity.quartz.Param; + +import java.util.List; + +/** + * 检验影刀参数是否是json数组格式 + * + * @author rch + * @create 2022-08-17 + */ +public class YdParamsCheck { + + /** + * params 是json格式则返回true 否则返回false + * @param str + * @return + */ + public static Boolean paramIsJson(String str) { + + if (ObjectUtil.isEmpty(str)) { + return false; + } + + if (!JSONUtil.isJson(str)) { + return false; + } + + Boss boss = JSONUtil.toBean(str, Boss.class); + if (ObjectUtil.isEmpty(boss) || ObjectUtil.isEmpty(boss.getParams())) { + return false; + } + + List paramList = boss.getParams(); + for (Param param:paramList) { + if (ObjectUtil.isEmpty(param)) { + return false; + } + } + + return true; + } + + public static void main(String[] args) { + String str = "{\"accountName\":\"linbiaoyuan@vogocm\",\"applyId\":2,\"params\":1}"; + str = "{\"accountName\":\"linbiaoyuan@vogocm\",\"applyId\":2,\"params\":[{\"name\":\"id\",\"value\":\"1\",\"type\":\"str\"}]}"; + Boolean boolean1 = paramIsJson(str); + System.out.println("==========boolean1:" + boolean1); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/YdSignUtil.java b/wjcy-common/src/main/java/me/zhengjie/utils/YdSignUtil.java new file mode 100644 index 0000000..7acc18d --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/YdSignUtil.java @@ -0,0 +1,94 @@ +package me.zhengjie.utils; + +import cn.hutool.core.util.ObjectUtil; +import me.zhengjie.entity.YdSign; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.Charset; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Date; + +/** + * 影刀鉴权工具类 + * + * @author rch + * @create 2022-07-26 + */ +public class YdSignUtil { + + private static final char[] DIGITS_LOWER = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};; + + private static final String UTF8_NAME = "UTF-8"; + + private static final Charset UTF8_CHARSET = Charset.forName(UTF8_NAME); + + + public static String getSign(YdSign ydSign) { + String sign = null; + if (ObjectUtil.isEmpty(ydSign) + || ObjectUtil.isEmpty(ydSign.getAccessKeyId()) + || ObjectUtil.isEmpty(ydSign.getTimestamp()) + || ObjectUtil.isEmpty(ydSign.getBodyMd5()) + || ObjectUtil.isEmpty(ydSign.getAccessKeySecret())) { + return sign; + } + + //由回调接口回传 + long timestamp = ydSign.getTimestamp(); + //影刀控制台配置的accessKeyId + String accessKeyId = ydSign.getAccessKeyId(); + //影刀控制台配置的accessKeySecret + String accessKeySecret = ydSign.getAccessKeySecret(); + //由回调接口回传 + String bodyMd5 = ydSign.getBodyMd5(); + DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + Date date = new Date(timestamp); + LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()); + + System.out.println(bodyMd5); + StringBuilder sb = new StringBuilder(); + sb.append("accessKeyId="); + sb.append(accessKeyId); + sb.append("&bodyMd5="); + sb.append(bodyMd5); + sb.append("×tamp="); + sb.append(pattern.format(localDateTime)); + + String originalStr = sb.toString(); + byte[] keyBytes = accessKeySecret.getBytes(); + SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "HmacSHA1"); + try { + Mac mac = Mac.getInstance("HmacSHA1"); + mac.init(secretKey); + byte[] rawHmac = mac.doFinal(originalStr.getBytes(UTF8_CHARSET)); + sign = encodeHex(rawHmac); + System.out.println("sign: " + sign); + } catch (Exception e) { + e.printStackTrace(); + return sign; + } + + return sign; + } + + /** + * 转换16进制 + * + * @param data + * @return + */ + private static String encodeHex(byte[] data) { + int l = data.length; + char[] out = new char[l << 1]; + int i = 0; + + for(int var5 = 0; i < l; ++i) { + out[var5++] = DIGITS_LOWER[(240 & data[i]) >>> 4]; + out[var5++] = DIGITS_LOWER[15 & data[i]]; + } + return new String(out); + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/enums/CodeBiEnum.java b/wjcy-common/src/main/java/me/zhengjie/utils/enums/CodeBiEnum.java new file mode 100644 index 0000000..661e0a0 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/enums/CodeBiEnum.java @@ -0,0 +1,50 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + *

+ * 验证码业务场景 + *

+ * @author Zheng Jie + * @date 2020-05-02 + */ +@Getter +@AllArgsConstructor +public enum CodeBiEnum { + + /* 旧邮箱修改邮箱 */ + ONE(1, "旧邮箱修改邮箱"), + + /* 通过邮箱修改密码 */ + TWO(2, "通过邮箱修改密码"); + + private final Integer code; + private final String description; + + public static CodeBiEnum find(Integer code) { + for (CodeBiEnum value : CodeBiEnum.values()) { + if (code.equals(value.getCode())) { + return value; + } + } + return null; + } + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/enums/CodeEnum.java b/wjcy-common/src/main/java/me/zhengjie/utils/enums/CodeEnum.java new file mode 100644 index 0000000..916862a --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/enums/CodeEnum.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + *

+ * 验证码业务场景对应的 Redis 中的 key + *

+ * @author Zheng Jie + * @date 2020-05-02 + */ +@Getter +@AllArgsConstructor +public enum CodeEnum { + + /* 通过手机号码重置邮箱 */ + PHONE_RESET_EMAIL_CODE("phone_reset_email_code_", "通过手机号码重置邮箱"), + + /* 通过旧邮箱重置邮箱 */ + EMAIL_RESET_EMAIL_CODE("email_reset_email_code_", "通过旧邮箱重置邮箱"), + + /* 通过手机号码重置密码 */ + PHONE_RESET_PWD_CODE("phone_reset_pwd_code_", "通过手机号码重置密码"), + + /* 通过邮箱重置密码 */ + EMAIL_RESET_PWD_CODE("email_reset_pwd_code_", "通过邮箱重置密码"); + + private final String key; + private final String description; +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/enums/DataScopeEnum.java b/wjcy-common/src/main/java/me/zhengjie/utils/enums/DataScopeEnum.java new file mode 100644 index 0000000..5352b7b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/enums/DataScopeEnum.java @@ -0,0 +1,53 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + *

+ * 数据权限枚举 + *

+ * @author Zheng Jie + * @date 2020-05-07 + */ +@Getter +@AllArgsConstructor +public enum DataScopeEnum { + + /* 全部的数据权限 */ + ALL("全部", "全部的数据权限"), + + /* 自己部门的数据权限 */ + THIS_LEVEL("本级", "自己部门的数据权限"), + + /* 自定义的数据权限 */ + CUSTOMIZE("自定义", "自定义的数据权限"); + + private final String value; + private final String description; + + public static DataScopeEnum find(String val) { + for (DataScopeEnum dataScopeEnum : DataScopeEnum.values()) { + if (val.equals(dataScopeEnum.getValue())) { + return dataScopeEnum; + } + } + return null; + } + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/enums/RequestMethodEnum.java b/wjcy-common/src/main/java/me/zhengjie/utils/enums/RequestMethodEnum.java new file mode 100644 index 0000000..1b65c78 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/enums/RequestMethodEnum.java @@ -0,0 +1,74 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @author Zheng Jie + * @website https://el-admin.vip + * @description + * @date 2020-06-10 + **/ +@Getter +@AllArgsConstructor +public enum RequestMethodEnum { + + /** + * 搜寻 @AnonymousGetMapping + */ + GET("GET"), + + /** + * 搜寻 @AnonymousPostMapping + */ + POST("POST"), + + /** + * 搜寻 @AnonymousPutMapping + */ + PUT("PUT"), + + /** + * 搜寻 @AnonymousPatchMapping + */ + PATCH("PATCH"), + + /** + * 搜寻 @AnonymousDeleteMapping + */ + DELETE("DELETE"), + + /** + * 否则就是所有 Request 接口都放行 + */ + ALL("All"); + + /** + * Request 类型 + */ + private final String type; + + public static RequestMethodEnum find(String type) { + for (RequestMethodEnum value : RequestMethodEnum.values()) { + if (type.equals(value.getType())) { + return value; + } + } + return ALL; + } +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/excel/ExcelClassField.java b/wjcy-common/src/main/java/me/zhengjie/utils/excel/ExcelClassField.java new file mode 100644 index 0000000..2107f6e --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/excel/ExcelClassField.java @@ -0,0 +1,79 @@ +package me.zhengjie.utils.excel; + +import java.util.LinkedHashMap; + +/** + * ExcelClassField + * + * @author rch + * @create 2022-06-22 + */ +public class ExcelClassField { + + /** 字段名称 */ + private String fieldName; + + /** 表头名称 */ + private String name; + + /** 映射关系 */ + private LinkedHashMap kvMap; + + /** 示例值 */ + private Object example; + + /** 排序 */ + private int sort; + + /** 是否为注解字段:0-否,1-是 */ + private int hasAnnotation; + + public String getFieldName() { + return fieldName; + } + + public void setFieldName(String fieldName) { + this.fieldName = fieldName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public LinkedHashMap getKvMap() { + return kvMap; + } + + public void setKvMap(LinkedHashMap kvMap) { + this.kvMap = kvMap; + } + + public Object getExample() { + return example; + } + + public void setExample(Object example) { + this.example = example; + } + + public int getSort() { + return sort; + } + + public void setSort(int sort) { + this.sort = sort; + } + + public int getHasAnnotation() { + return hasAnnotation; + } + + public void setHasAnnotation(int hasAnnotation) { + this.hasAnnotation = hasAnnotation; + } + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/excel/ExcelExport.java b/wjcy-common/src/main/java/me/zhengjie/utils/excel/ExcelExport.java new file mode 100644 index 0000000..706d95b --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/excel/ExcelExport.java @@ -0,0 +1,30 @@ +package me.zhengjie.utils.excel; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * ExcelExport + * + * @author rch + * @create 2022-06-22 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ExcelExport { + + /** 字段名称 */ + String value(); + + /** 导出排序先后: 数字越小越靠前(默认按Java类字段顺序导出) */ + int sort() default 0; + + /** 导出映射,格式如:0-未知;1-男;2-女 */ + String kv() default ""; + + /** 导出模板示例值(有值的话,直接取该值,不做映射) */ + String example() default ""; + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/excel/ExcelImport.java b/wjcy-common/src/main/java/me/zhengjie/utils/excel/ExcelImport.java new file mode 100644 index 0000000..5110dad --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/excel/ExcelImport.java @@ -0,0 +1,34 @@ +package me.zhengjie.utils.excel; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * ExcelImport + * + * @author rch + * @create 2022-06-22 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ExcelImport { + + /** 字段名称 */ + String value(); + + /** 导出映射,格式如:0-未知;1-男;2-女 */ + String kv() default ""; + + /** 是否为必填字段(默认为非必填) */ + boolean required() default false; + + /** 最大长度(默认255) */ + int maxLength() default 255; + + /** 导入唯一性验证(多个字段则取联合验证) */ + boolean unique() default false; + +} diff --git a/wjcy-common/src/main/java/me/zhengjie/utils/excel/ExcelUtils.java b/wjcy-common/src/main/java/me/zhengjie/utils/excel/ExcelUtils.java new file mode 100644 index 0000000..59b1998 --- /dev/null +++ b/wjcy-common/src/main/java/me/zhengjie/utils/excel/ExcelUtils.java @@ -0,0 +1,993 @@ +package me.zhengjie.utils.excel; + +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import org.apache.poi.hssf.usermodel.HSSFDataValidation; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.usermodel.ClientAnchor.AnchorType; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFClientAnchor; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.lang.reflect.Field; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.net.URL; +import java.text.NumberFormat; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.Map.Entry; +import java.util.regex.Pattern; + +/** + * Excel导入导出工具类 + * + * @author rch + * @create 2022-06-22 + */ +public class ExcelUtils { + private static final String XLSX = ".xlsx"; + private static final String XLS = ".xls"; + public static final String ROW_MERGE = "row_merge"; + public static final String COLUMN_MERGE = "column_merge"; + private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; + private static final String ROW_NUM = "rowNum"; + private static final String ROW_DATA = "rowData"; + private static final String ROW_TIPS = "rowTips"; + private static final int CELL_OTHER = 0; + private static final int CELL_ROW_MERGE = 1; + private static final int CELL_COLUMN_MERGE = 2; + private static final int IMG_HEIGHT = 30; + private static final int IMG_WIDTH = 30; + private static final char LEAN_LINE = '/'; + private static final int BYTES_DEFAULT_LENGTH = 10240; + private static final NumberFormat NUMBER_FORMAT = NumberFormat.getNumberInstance(); + + + public static List readFile(File file, Class clazz) throws Exception { + JSONArray array = readFile(file); + return getBeanList(array, clazz); + } + + public static List readMultipartFile(MultipartFile mFile, Class clazz) throws Exception { + JSONArray array = readMultipartFile(mFile); + return getBeanList(array, clazz); + } + + public static JSONArray readFile(File file) throws Exception { + return readExcel(null, file); + } + + public static JSONArray readMultipartFile(MultipartFile mFile) throws Exception { + return readExcel(mFile, null); + } + + public static Map readFileManySheet(File file) throws Exception { + return readExcelManySheet(null, file); + } + + public static Map readFileManySheet(MultipartFile file) throws Exception { + return readExcelManySheet(file, null); + } + + private static List getBeanList(JSONArray array, Class clazz) throws Exception { + List list = new ArrayList<>(); + Map uniqueMap = new HashMap<>(16); + for (int i = 0; i < array.size(); i++) { + list.add(getBean(clazz, array.getJSONObject(i), uniqueMap)); + } + return list; + } + + /** + * 获取每个对象的数据 + */ + private static T getBean(Class c, JSONObject obj, Map uniqueMap) throws Exception { + T t = c.newInstance(); + Field[] fields = c.getDeclaredFields(); + List errMsgList = new ArrayList<>(); + boolean hasRowTipsField = false; + StringBuilder uniqueBuilder = new StringBuilder(); + int rowNum = 0; + for (Field field : fields) { + // 行号 + if (field.getName().equals(ROW_NUM)) { + rowNum = obj.getInteger(ROW_NUM); + field.setAccessible(true); + field.set(t, rowNum); + continue; + } + // 是否需要设置异常信息 + if (field.getName().equals(ROW_TIPS)) { + hasRowTipsField = true; + continue; + } + // 原始数据 + if (field.getName().equals(ROW_DATA)) { + field.setAccessible(true); + field.set(t, obj.toString()); + continue; + } + // 设置对应属性值 + setFieldValue(t, field, obj, uniqueBuilder, errMsgList); + } + // 数据唯一性校验 + if (uniqueBuilder.length() > 0) { + if (uniqueMap.containsValue(uniqueBuilder.toString())) { + Set rowNumKeys = uniqueMap.keySet(); + for (Integer num : rowNumKeys) { + if (uniqueMap.get(num).equals(uniqueBuilder.toString())) { + errMsgList.add(String.format("数据唯一性校验失败,(%s)与第%s行重复)", uniqueBuilder, num)); + } + } + } else { + uniqueMap.put(rowNum, uniqueBuilder.toString()); + } + } + // 失败处理 + if (errMsgList.isEmpty() && !hasRowTipsField) { + return t; + } + StringBuilder sb = new StringBuilder(); + int size = errMsgList.size(); + for (int i = 0; i < size; i++) { + if (i == size - 1) { + sb.append(errMsgList.get(i)); + } else { + sb.append(errMsgList.get(i)).append(";"); + } + } + // 设置错误信息 + for (Field field : fields) { + if (field.getName().equals(ROW_TIPS)) { + field.setAccessible(true); + field.set(t, sb.toString()); + } + } + return t; + } + + private static void setFieldValue(T t, Field field, JSONObject obj, StringBuilder uniqueBuilder, List errMsgList) { + // 获取 ExcelImport 注解属性 + ExcelImport annotation = field.getAnnotation(ExcelImport.class); + if (annotation == null) { + return; + } + String cname = annotation.value(); + if (cname.trim().length() == 0) { + return; + } + // 获取具体值 + String val = null; + if (obj.containsKey(cname)) { + val = getString(obj.getString(cname)); + } + if (val == null) { + return; + } + field.setAccessible(true); + // 判断是否必填 + boolean require = annotation.required(); + if (require && val.isEmpty()) { + errMsgList.add(String.format("[%s]不能为空", cname)); + return; + } + // 数据唯一性获取 + boolean unique = annotation.unique(); + if (unique) { + if (uniqueBuilder.length() > 0) { + uniqueBuilder.append("--").append(val); + } else { + uniqueBuilder.append(val); + } + } + // 判断是否超过最大长度 + int maxLength = annotation.maxLength(); + if (maxLength > 0 && val.length() > maxLength) { + errMsgList.add(String.format("[%s]长度不能超过%s个字符(当前%s个字符)", cname, maxLength, val.length())); + } + // 判断当前属性是否有映射关系 + LinkedHashMap kvMap = getKvMap(annotation.kv()); + if (!kvMap.isEmpty()) { + boolean isMatch = false; + for (String key : kvMap.keySet()) { + if (kvMap.get(key).equals(val)) { + val = key; + isMatch = true; + break; + } + } + if (!isMatch) { + errMsgList.add(String.format("[%s]的值不正确(当前值为%s)", cname, val)); + return; + } + } + // 其余情况根据类型赋值 + String fieldClassName = field.getType().getSimpleName(); + try { + if ("String".equalsIgnoreCase(fieldClassName)) { + field.set(t, val); + } else if ("boolean".equalsIgnoreCase(fieldClassName)) { + field.set(t, Boolean.valueOf(val)); + } else if ("int".equalsIgnoreCase(fieldClassName) || "Integer".equals(fieldClassName)) { + try { + field.set(t, Integer.valueOf(val)); + } catch (NumberFormatException e) { + errMsgList.add(String.format("[%s]的值格式不正确(当前值为%s)", cname, val)); + } + } else if ("double".equalsIgnoreCase(fieldClassName)) { + field.set(t, Double.valueOf(val)); + } else if ("long".equalsIgnoreCase(fieldClassName)) { + field.set(t, Long.valueOf(val)); + } else if ("BigDecimal".equalsIgnoreCase(fieldClassName)) { + field.set(t, new BigDecimal(val)); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static Map readExcelManySheet(MultipartFile mFile, File file) throws IOException { + Workbook book = getWorkbook(mFile, file); + if (book == null) { + return Collections.emptyMap(); + } + Map map = new LinkedHashMap<>(); + for (int i = 0; i < book.getNumberOfSheets(); i++) { + Sheet sheet = book.getSheetAt(i); + JSONArray arr = readSheet(sheet); + map.put(sheet.getSheetName(), arr); + } + book.close(); + return map; + } + + private static JSONArray readExcel(MultipartFile mFile, File file) throws IOException { + Workbook book = getWorkbook(mFile, file); + if (book == null) { + return new JSONArray(); + } + JSONArray array = readSheet(book.getSheetAt(0)); + book.close(); + return array; + } + + private static Workbook getWorkbook(MultipartFile mFile, File file) throws IOException { + boolean fileNotExist = (file == null || !file.exists()); + if (mFile == null && fileNotExist) { + return null; + } + // 解析表格数据 + InputStream in; + String fileName; + if (mFile != null) { + // 上传文件解析 + in = mFile.getInputStream(); + fileName = getString(mFile.getOriginalFilename()).toLowerCase(); + } else { + // 本地文件解析 + in = new FileInputStream(file); + fileName = file.getName().toLowerCase(); + } + Workbook book; + if (fileName.endsWith(XLSX)) { + book = new XSSFWorkbook(in); + } else if (fileName.endsWith(XLS)) { + POIFSFileSystem poifsFileSystem = new POIFSFileSystem(in); + book = new HSSFWorkbook(poifsFileSystem); + } else { + return null; + } + in.close(); + return book; + } + + private static JSONArray readSheet(Sheet sheet) { + // 首行下标 + int rowStart = sheet.getFirstRowNum(); + // 尾行下标 + int rowEnd = sheet.getLastRowNum(); + // 获取表头行 + Row headRow = sheet.getRow(rowStart); + if (headRow == null) { + return new JSONArray(); + } + int cellStart = headRow.getFirstCellNum(); + int cellEnd = headRow.getLastCellNum(); + Map keyMap = new HashMap<>(16); + for (int j = cellStart; j < cellEnd; j++) { + // 获取表头数据 + String val = getCellValue(headRow.getCell(j)); + if (val != null && val.trim().length() != 0) { + keyMap.put(j, val); + } + } + // 如果表头没有数据则不进行解析 + if (keyMap.isEmpty()) { + return (JSONArray) Collections.emptyList(); + } + // 获取每行JSON对象的值 + JSONArray array = new JSONArray(); + // 如果首行与尾行相同,表明只有一行,返回表头数据 + if (rowStart == rowEnd) { + JSONObject obj = new JSONObject(); + // 添加行号 + obj.put(ROW_NUM, 1); + for (int i : keyMap.keySet()) { + obj.put(keyMap.get(i), ""); + } + array.add(obj); + return array; + } + for (int i = rowStart + 1; i <= rowEnd; i++) { + Row eachRow = sheet.getRow(i); + JSONObject obj = new JSONObject(); + // 添加行号 + obj.put(ROW_NUM, i + 1); + StringBuilder sb = new StringBuilder(); + for (int k = cellStart; k < cellEnd; k++) { + if (eachRow != null) { + String val = getCellValue(eachRow.getCell(k)); + // 所有数据添加到里面,用于判断该行是否为空 + sb.append(val); + obj.put(keyMap.get(k), val); + } + } + if (sb.length() > 0) { + array.add(obj); + } + } + return array; + } + + private static String getCellValue(Cell cell) { + // 空白或空 + if (cell == null || cell.getCellTypeEnum() == CellType.BLANK) { + return ""; + } + // String类型 + if (cell.getCellTypeEnum() == CellType.STRING) { + String val = cell.getStringCellValue(); + if (val == null || val.trim().length() == 0) { + return ""; + } + return val.trim(); + } + // 数字类型 + if (cell.getCellTypeEnum() == CellType.NUMERIC) { + String s = cell.getNumericCellValue() + ""; + // 去掉尾巴上的小数点0 + if (Pattern.matches(".*\\.0*", s)) { + return s.split("\\.")[0]; + } else { + return s; + } + } + // 布尔值类型 + if (cell.getCellTypeEnum() == CellType.BOOLEAN) { + return cell.getBooleanCellValue() + ""; + } + // 错误类型 + return cell.getCellFormula(); + } + + public static void exportTemplate(HttpServletResponse response, String fileName, Class clazz) { + exportTemplate(response, fileName, fileName, clazz, false); + } + + public static void exportTemplate(HttpServletResponse response, String fileName, String sheetName, + Class clazz) { + exportTemplate(response, fileName, sheetName, clazz, false); + } + + public static void exportTemplate(HttpServletResponse response, String fileName, Class clazz, + boolean isContainExample) { + exportTemplate(response, fileName, fileName, clazz, isContainExample); + } + + public static void exportTemplate(HttpServletResponse response, String fileName, String sheetName, + Class clazz, boolean isContainExample) { + // 获取表头字段 + List headFieldList = getExcelClassFieldList(clazz); + // 获取表头数据和示例数据 + List> sheetDataList = new ArrayList<>(); + List headList = new ArrayList<>(); + List exampleList = new ArrayList<>(); + Map> selectMap = new LinkedHashMap<>(); + for (int i = 0; i < headFieldList.size(); i++) { + ExcelClassField each = headFieldList.get(i); + headList.add(each.getName()); + exampleList.add(each.getExample()); + LinkedHashMap kvMap = each.getKvMap(); + if (kvMap != null && kvMap.size() > 0) { + selectMap.put(i, new ArrayList<>(kvMap.values())); + } + } + sheetDataList.add(headList); + if (isContainExample) { + sheetDataList.add(exampleList); + } + // 导出数据 + export(response, fileName, sheetName, sheetDataList, selectMap); + } + + private static List getExcelClassFieldList(Class clazz) { + // 解析所有字段 + Field[] fields = clazz.getDeclaredFields(); + boolean hasExportAnnotation = false; + Map> map = new LinkedHashMap<>(); + List sortList = new ArrayList<>(); + for (Field field : fields) { + ExcelClassField cf = getExcelClassField(field); + if (cf.getHasAnnotation() == 1) { + hasExportAnnotation = true; + } + int sort = cf.getSort(); + if (map.containsKey(sort)) { + map.get(sort).add(cf); + } else { + List list = new ArrayList<>(); + list.add(cf); + sortList.add(sort); + map.put(sort, list); + } + } + Collections.sort(sortList); + // 获取表头 + List headFieldList = new ArrayList<>(); + if (hasExportAnnotation) { + for (Integer sort : sortList) { + for (ExcelClassField cf : map.get(sort)) { + if (cf.getHasAnnotation() == 1) { + headFieldList.add(cf); + } + } + } + } else { + headFieldList.addAll(map.get(0)); + } + return headFieldList; + } + + private static ExcelClassField getExcelClassField(Field field) { + ExcelClassField cf = new ExcelClassField(); + String fieldName = field.getName(); + cf.setFieldName(fieldName); + ExcelExport annotation = field.getAnnotation(ExcelExport.class); + // 无 ExcelExport 注解情况 + if (annotation == null) { + cf.setHasAnnotation(0); + cf.setName(fieldName); + cf.setSort(0); + return cf; + } + // 有 ExcelExport 注解情况 + cf.setHasAnnotation(1); + cf.setName(annotation.value()); + String example = getString(annotation.example()); + if (!example.isEmpty()) { + if (isNumeric(example)) { + cf.setExample(Double.valueOf(example)); + } else { + cf.setExample(example); + } + } else { + cf.setExample(""); + } + cf.setSort(annotation.sort()); + // 解析映射 + String kv = getString(annotation.kv()); + cf.setKvMap(getKvMap(kv)); + return cf; + } + + private static LinkedHashMap getKvMap(String kv) { + LinkedHashMap kvMap = new LinkedHashMap<>(); + if (kv.isEmpty()) { + return kvMap; + } + String[] kvs = kv.split(";"); + if (kvs.length == 0) { + return kvMap; + } + for (String each : kvs) { + String[] eachKv = getString(each).split("-"); + if (eachKv.length != 2) { + continue; + } + String k = eachKv[0]; + String v = eachKv[1]; + if (k.isEmpty() || v.isEmpty()) { + continue; + } + kvMap.put(k, v); + } + return kvMap; + } + + /** + * 导出表格到本地 + * + * @param file 本地文件对象 + * @param sheetData 导出数据 + */ + public static void exportFile(File file, List> sheetData) { + if (file == null) { + System.out.println("文件创建失败"); + return; + } + if (sheetData == null) { + sheetData = new ArrayList<>(); + } + Map>> map = new HashMap<>(16); + map.put(file.getName(), sheetData); + export(null, file, file.getName(), map, null); + } + + /** + * 导出表格到本地 + * + * @param 导出数据类似,和K类型保持一致 + * @param filePath 文件父路径(如:D:/doc/excel/) + * @param fileName 文件名称(不带尾缀,如:学生表) + * @param list 导出数据 + * @throws IOException IO异常 + */ + public static File exportFile(String filePath, String fileName, List list) throws IOException { + File file = getFile(filePath, fileName); + List> sheetData = getSheetData(list); + exportFile(file, sheetData); + return file; + } + + /** + * 获取文件 + * + * @param filePath filePath 文件父路径(如:D:/doc/excel/) + * @param fileName 文件名称(不带尾缀,如:用户表) + * @return 本地File文件对象 + */ + private static File getFile(String filePath, String fileName) throws IOException { + String dirPath = getString(filePath); + String fileFullPath; + if (dirPath.isEmpty()) { + fileFullPath = fileName; + } else { + // 判定文件夹是否存在,如果不存在,则级联创建 + File dirFile = new File(dirPath); + if (!dirFile.exists()) { + dirFile.mkdirs(); + } + // 获取文件夹全名 + if (dirPath.endsWith(String.valueOf(LEAN_LINE))) { + fileFullPath = dirPath + fileName + XLSX; + } else { + fileFullPath = dirPath + LEAN_LINE + fileName + XLSX; + } + } + System.out.println(fileFullPath); + File file = new File(fileFullPath); + if (!file.exists()) { + file.createNewFile(); + } + return file; + } + + private static List> getSheetData(List list) { + // 获取表头字段 + List excelClassFieldList = getExcelClassFieldList(list.get(0).getClass()); + List headFieldList = new ArrayList<>(); + List headList = new ArrayList<>(); + Map headFieldMap = new HashMap<>(16); + for (ExcelClassField each : excelClassFieldList) { + String fieldName = each.getFieldName(); + headFieldList.add(fieldName); + headFieldMap.put(fieldName, each); + headList.add(each.getName()); + } + // 添加表头名称 + List> sheetDataList = new ArrayList<>(); + sheetDataList.add(headList); + // 获取表数据 + for (T t : list) { + Map fieldDataMap = getFieldDataMap(t); + Set fieldDataKeys = fieldDataMap.keySet(); + List rowList = new ArrayList<>(); + for (String headField : headFieldList) { + if (!fieldDataKeys.contains(headField)) { + continue; + } + Object data = fieldDataMap.get(headField); + if (data == null) { + rowList.add(""); + continue; + } + ExcelClassField cf = headFieldMap.get(headField); + // 判断是否有映射关系 + LinkedHashMap kvMap = cf.getKvMap(); + if (kvMap == null || kvMap.isEmpty()) { + rowList.add(data); + continue; + } + String val = kvMap.get(data.toString()); + if (isNumeric(val)) { + rowList.add(Double.valueOf(val)); + } else { + rowList.add(val); + } + } + sheetDataList.add(rowList); + } + return sheetDataList; + } + + private static Map getFieldDataMap(T t) { + Map map = new HashMap<>(16); + Field[] fields = t.getClass().getDeclaredFields(); + try { + for (Field field : fields) { + String fieldName = field.getName(); + field.setAccessible(true); + Object object = field.get(t); + map.put(fieldName, object); + } + } catch (IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + } + return map; + } + + public static void exportEmpty(HttpServletResponse response, String fileName) { + List> sheetDataList = new ArrayList<>(); + List headList = new ArrayList<>(); + headList.add("导出无数据"); + sheetDataList.add(headList); + export(response, fileName, sheetDataList); + } + + public static void export(HttpServletResponse response, String fileName, List> sheetDataList) { + export(response, fileName, fileName, sheetDataList, null); + } + + public static void exportManySheet(HttpServletResponse response, String fileName, Map>> sheetMap) { + export(response, null, fileName, sheetMap, null); + } + + + public static void export(HttpServletResponse response, String fileName, String sheetName, + List> sheetDataList) { + export(response, fileName, sheetName, sheetDataList, null); + } + + public static void export(HttpServletResponse response, String fileName, String sheetName, + List> sheetDataList, Map> selectMap) { + + Map>> map = new HashMap<>(16); + map.put(sheetName, sheetDataList); + export(response, null, fileName, map, selectMap); + } + + public static void export(HttpServletResponse response, String fileName, List list, Class template) { + // list 是否为空 + boolean lisIsEmpty = list == null || list.isEmpty(); + // 如果模板数据为空,且导入的数据为空,则导出空文件 + if (template == null && lisIsEmpty) { + exportEmpty(response, fileName); + return; + } + // 如果 list 数据,则导出模板数据 + if (lisIsEmpty) { + exportTemplate(response, fileName, template); + return; + } + // 导出数据 + List> sheetDataList = getSheetData(list); + export(response, fileName, sheetDataList); + } + + public static void export(HttpServletResponse response, String fileName, List> sheetDataList, Map> selectMap) { + export(response, fileName, fileName, sheetDataList, selectMap); + } + + private static void export(HttpServletResponse response, File file, String fileName, + Map>> sheetMap, Map> selectMap) { + // 整个 Excel 表格 book 对象 + SXSSFWorkbook book = new SXSSFWorkbook(); + // 每个 Sheet 页 + Set>>> entries = sheetMap.entrySet(); + for (Entry>> entry : entries) { + List> sheetDataList = entry.getValue(); + Sheet sheet = book.createSheet(entry.getKey()); + Drawing patriarch = sheet.createDrawingPatriarch(); + // 设置表头背景色(灰色) + CellStyle headStyle = book.createCellStyle(); + headStyle.setFillForegroundColor(IndexedColors.GREY_80_PERCENT.index); + headStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + headStyle.setAlignment(HorizontalAlignment.CENTER); + headStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.index); + // 设置表身背景色(默认色) + CellStyle rowStyle = book.createCellStyle(); + rowStyle.setAlignment(HorizontalAlignment.CENTER); + rowStyle.setVerticalAlignment(VerticalAlignment.CENTER); + // 设置表格列宽度(默认为15个字节) + sheet.setDefaultColumnWidth(15); + // 创建合并算法数组 + int rowLength = sheetDataList.size(); + int columnLength = sheetDataList.get(0).size(); + int[][] mergeArray = new int[rowLength][columnLength]; + for (int i = 0; i < sheetDataList.size(); i++) { + // 每个 Sheet 页中的行数据 + Row row = sheet.createRow(i); + List rowList = sheetDataList.get(i); + for (int j = 0; j < rowList.size(); j++) { + // 每个行数据中的单元格数据 + Object o = rowList.get(j); + int v = 0; + if (o instanceof URL) { + // 如果要导出图片的话, 链接需要传递 URL 对象 + setCellPicture(book, row, patriarch, i, j, (URL) o); + } else { + Cell cell = row.createCell(j); + if (i == 0) { + // 第一行为表头行,采用灰色底背景 + v = setCellValue(cell, o, headStyle); + } else { + // 其他行为数据行,默认白底色 + v = setCellValue(cell, o, rowStyle); + } + } + mergeArray[i][j] = v; + } + } + // 合并单元格 + mergeCells(sheet, mergeArray); + // 设置下拉列表 + setSelect(sheet, selectMap); + } + // 写数据 + if (response != null) { + // 前端导出 + try { + write(response, book, fileName); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + // 本地导出 + FileOutputStream fos; + try { + fos = new FileOutputStream(file); + ByteArrayOutputStream ops = new ByteArrayOutputStream(); + book.write(ops); + fos.write(ops.toByteArray()); + fos.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + /** + * 合并当前Sheet页的单元格 + * + * @param sheet 当前 sheet 页 + * @param mergeArray 合并单元格算法 + */ + private static void mergeCells(Sheet sheet, int[][] mergeArray) { + // 横向合并 + for (int x = 0; x < mergeArray.length; x++) { + int[] arr = mergeArray[x]; + boolean merge = false; + int y1 = 0; + int y2 = 0; + for (int y = 0; y < arr.length; y++) { + int value = arr[y]; + if (value == CELL_COLUMN_MERGE) { + if (!merge) { + y1 = y; + } + y2 = y; + merge = true; + } else { + merge = false; + if (y1 > 0) { + sheet.addMergedRegion(new CellRangeAddress(x, x, (y1 - 1), y2)); + } + y1 = 0; + y2 = 0; + } + } + if (y1 > 0) { + sheet.addMergedRegion(new CellRangeAddress(x, x, (y1 - 1), y2)); + } + } + // 纵向合并 + int xLen = mergeArray.length; + int yLen = mergeArray[0].length; + for (int y = 0; y < yLen; y++) { + boolean merge = false; + int x1 = 0; + int x2 = 0; + for (int x = 0; x < xLen; x++) { + int value = mergeArray[x][y]; + if (value == CELL_ROW_MERGE) { + if (!merge) { + x1 = x; + } + x2 = x; + merge = true; + } else { + merge = false; + if (x1 > 0) { + sheet.addMergedRegion(new CellRangeAddress((x1 - 1), x2, y, y)); + } + x1 = 0; + x2 = 0; + } + } + if (x1 > 0) { + sheet.addMergedRegion(new CellRangeAddress((x1 - 1), x2, y, y)); + } + } + } + + private static void write(HttpServletResponse response, SXSSFWorkbook book, String fileName) throws IOException { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + String name = new String(fileName.getBytes("GBK"), "ISO8859_1") + XLSX; + response.addHeader("Content-Disposition", "attachment;filename=" + name); + ServletOutputStream out = response.getOutputStream(); + book.write(out); + out.flush(); + out.close(); + } + + private static int setCellValue(Cell cell, Object o, CellStyle style) { + // 设置样式 + cell.setCellStyle(style); + // 数据为空时 + if (ObjectUtil.isEmpty(o)) { + cell.setCellType(CellType.STRING); + cell.setCellValue(""); + return CELL_OTHER; + } + // 是否为字符串 + if (o instanceof String) { + String s = o.toString(); + if (isNumeric(s)) { + cell.setCellType(CellType.NUMERIC); + cell.setCellValue(Double.parseDouble(s)); + return CELL_OTHER; + } else { + cell.setCellType(CellType.STRING); + cell.setCellValue(s); + } + if (s.equals(ROW_MERGE)) { + return CELL_ROW_MERGE; + } else if (s.equals(COLUMN_MERGE)) { + return CELL_COLUMN_MERGE; + } else { + return CELL_OTHER; + } + } + // 是否为字符串 + if (o instanceof Integer || o instanceof Long || o instanceof Double || o instanceof Float) { + cell.setCellType(CellType.NUMERIC); + cell.setCellValue(Double.parseDouble(o.toString())); + return CELL_OTHER; + } + // 是否为Boolean + if (o instanceof Boolean) { + cell.setCellType(CellType.BOOLEAN); + cell.setCellValue((Boolean) o); + return CELL_OTHER; + } + // 如果是BigDecimal,则默认3位小数 + if (o instanceof BigDecimal) { + cell.setCellType(CellType.NUMERIC); + cell.setCellValue(((BigDecimal) o).setScale(3, RoundingMode.HALF_UP).doubleValue()); + return CELL_OTHER; + } + // 如果是Date数据,则显示格式化数据 + if (o instanceof Date) { + cell.setCellType(CellType.STRING); + cell.setCellValue(formatDate((Date) o)); + return CELL_OTHER; + } + // 如果是其他,则默认字符串类型 + cell.setCellType(CellType.STRING); + cell.setCellValue(o.toString()); + return CELL_OTHER; + } + + private static void setCellPicture(SXSSFWorkbook wb, Row sr, Drawing patriarch, int x, int y, URL url) { + // 设置图片宽高 + sr.setHeight((short) (IMG_WIDTH * IMG_HEIGHT)); + // (jdk1.7版本try中定义流可自动关闭) + try (InputStream is = url.openStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + byte[] buff = new byte[BYTES_DEFAULT_LENGTH]; + int rc; + while ((rc = is.read(buff, 0, BYTES_DEFAULT_LENGTH)) > 0) { + outputStream.write(buff, 0, rc); + } + // 设置图片位置 + XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, y, x, y + 1, x + 1); + // 设置这个,图片会自动填满单元格的长宽 + anchor.setAnchorType(AnchorType.MOVE_AND_RESIZE); + patriarch.createPicture(anchor, wb.addPicture(outputStream.toByteArray(), HSSFWorkbook.PICTURE_TYPE_JPEG)); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static String formatDate(Date date) { + if (date == null) { + return ""; + } + SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT); + return format.format(date); + } + + private static void setSelect(Sheet sheet, Map> selectMap) { + if (selectMap == null || selectMap.isEmpty()) { + return; + } + Set>> entrySet = selectMap.entrySet(); + for (Entry> entry : entrySet) { + int y = entry.getKey(); + List list = entry.getValue(); + if (list == null || list.isEmpty()) { + continue; + } + String[] arr = new String[list.size()]; + for (int i = 0; i < list.size(); i++) { + arr[i] = list.get(i); + } + DataValidationHelper helper = sheet.getDataValidationHelper(); + CellRangeAddressList addressList = new CellRangeAddressList(1, 65000, y, y); + DataValidationConstraint dvc = helper.createExplicitListConstraint(arr); + DataValidation dv = helper.createValidation(dvc, addressList); + if (dv instanceof HSSFDataValidation) { + dv.setSuppressDropDownArrow(false); + } else { + dv.setSuppressDropDownArrow(true); + dv.setShowErrorBox(true); + } + sheet.addValidationData(dv); + } + } + + private static boolean isNumeric(String str) { + if ("0.0".equals(str)) { + return true; + } + if (str.length() >= 15) { + return false; + } + for (int i = str.length(); --i >= 0; ) { + if (!Character.isDigit(str.charAt(i))) { + return false; + } + } + return true; + } + + private static String getString(String s) { + if (s == null) { + return ""; + } + if (s.isEmpty()) { + return s; + } + return s.trim(); + } +} diff --git a/wjcy-common/src/test/java/me/zhengjie/utils/EncryptUtilsTest.java b/wjcy-common/src/test/java/me/zhengjie/utils/EncryptUtilsTest.java new file mode 100644 index 0000000..f909d9d --- /dev/null +++ b/wjcy-common/src/test/java/me/zhengjie/utils/EncryptUtilsTest.java @@ -0,0 +1,32 @@ +package me.zhengjie.utils; + +import org.junit.Test; +import static org.junit.Assert.*; +import static me.zhengjie.utils.EncryptUtils.*; + +public class EncryptUtilsTest { + + /** + * 对称加密 + */ + @Test + public void testDesEncrypt() { + try { + assertEquals("7772841DC6099402", desEncrypt("123456")); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 对称解密 + */ + @Test + public void testDesDecrypt() { + try { + assertEquals("123456", desDecrypt("7772841DC6099402")); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/wjcy-common/src/test/java/me/zhengjie/utils/FileUtilTest.java b/wjcy-common/src/test/java/me/zhengjie/utils/FileUtilTest.java new file mode 100644 index 0000000..f069c15 --- /dev/null +++ b/wjcy-common/src/test/java/me/zhengjie/utils/FileUtilTest.java @@ -0,0 +1,36 @@ +package me.zhengjie.utils; + +import org.junit.Test; +import org.springframework.mock.web.MockMultipartFile; + +import static org.junit.Assert.*; +import static me.zhengjie.utils.FileUtil.*; + +public class FileUtilTest { + + @Test + public void testToFile() { + long retval = toFile(new MockMultipartFile("foo", (byte[]) null)).getTotalSpace(); + assertEquals(500695072768L, retval); + } + + @Test + public void testGetExtensionName() { + assertEquals("foo", getExtensionName("foo")); + assertEquals("exe", getExtensionName("bar.exe")); + } + + @Test + public void testGetFileNameNoEx() { + assertEquals("foo", getFileNameNoEx("foo")); + assertEquals("bar", getFileNameNoEx("bar.txt")); + } + + @Test + public void testGetSize() { + assertEquals("1000B ", getSize(1000)); + assertEquals("1.00KB ", getSize(1024)); + assertEquals("1.00MB ", getSize(1048576)); + assertEquals("1.00GB ", getSize(1073741824)); + } +} diff --git a/wjcy-common/src/test/java/me/zhengjie/utils/StringUtilsTest.java b/wjcy-common/src/test/java/me/zhengjie/utils/StringUtilsTest.java new file mode 100644 index 0000000..16de472 --- /dev/null +++ b/wjcy-common/src/test/java/me/zhengjie/utils/StringUtilsTest.java @@ -0,0 +1,66 @@ +package me.zhengjie.utils; + +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import org.junit.Test; +import org.springframework.mock.web.MockHttpServletRequest; +import org.thymeleaf.util.DateUtils; + +import java.text.SimpleDateFormat; +import java.util.Date; + +import static me.zhengjie.utils.StringUtils.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class StringUtilsTest { + + @Test + public void testToCamelCase() { + assertNull(toCamelCase(null)); + } + + @Test + public void testToCapitalizeCamelCase() { + assertNull(StringUtils.toCapitalizeCamelCase(null)); + assertEquals("HelloWorld", toCapitalizeCamelCase("hello_world")); + } + + @Test + public void testToUnderScoreCase() { + assertNull(StringUtils.toUnderScoreCase(null)); + assertEquals("hello_world", toUnderScoreCase("helloWorld")); + assertEquals("\u0000\u0000", toUnderScoreCase("\u0000\u0000")); + assertEquals("\u0000_a", toUnderScoreCase("\u0000A")); + } + + @Test + public void testGetWeekDay() { + SimpleDateFormat simpleDateformat = new SimpleDateFormat("E"); + assertEquals(simpleDateformat.format(new Date()), getWeekDay()); + } + + @Test + public void testGetIP() { + assertEquals("127.0.0.1", getIp(new MockHttpServletRequest())); + } + + + + @Test + public void test123() { + // 仅一次 + Date date = DateUtil.date(); + System.out.println("date:" + date); + DateTime dateTime = DateUtil.offsetSecond(date, 5); + System.out.println("dateTime:" + dateTime); + + String onlyOnce = CronUtils.onlyOnce(DateUtil.formatDateTime(dateTime)); + String onlyOnce1 = CronUtils.onlyOnce("2022-10-10 10:10:10"); + System.out.println(onlyOnce); + + // 一部到位 + String onlyOnce2 = CronUtils.onlyOnce(DateUtil.formatDateTime(DateUtil.offsetSecond(DateUtil.date(), 5))); + System.out.println(onlyOnce2); + } +} \ No newline at end of file diff --git a/wjcy-generator/pom.xml b/wjcy-generator/pom.xml new file mode 100644 index 0000000..87d7e4e --- /dev/null +++ b/wjcy-generator/pom.xml @@ -0,0 +1,39 @@ + + + + wjcy + me.zhengjie + 1.0 + + 4.0.0 + + wjcy-generator + 代码生成模块 + + + 1.9 + + + + + me.zhengjie + wjcy-common + 1.0 + + + + + org.springframework.boot + spring-boot-starter-freemarker + + + + + commons-configuration + commons-configuration + ${configuration.version} + + + \ No newline at end of file diff --git a/wjcy-generator/src/main/java/me/zhengjie/domain/ColumnInfo.java b/wjcy-generator/src/main/java/me/zhengjie/domain/ColumnInfo.java new file mode 100644 index 0000000..fdb962a --- /dev/null +++ b/wjcy-generator/src/main/java/me/zhengjie/domain/ColumnInfo.java @@ -0,0 +1,97 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import me.zhengjie.utils.GenUtil; +import javax.persistence.*; +import java.io.Serializable; + +/** + * 列的数据信息 + * @author Zheng Jie + * @date 2019-01-02 + */ +@Getter +@Setter +@Entity +@NoArgsConstructor +@Table(name = "code_column_config") +public class ColumnInfo implements Serializable { + + @Id + @Column(name = "column_id") + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ApiModelProperty(value = "表名") + private String tableName; + + @ApiModelProperty(value = "数据库字段名称") + private String columnName; + + @ApiModelProperty(value = "数据库字段类型") + private String columnType; + + @ApiModelProperty(value = "数据库字段键类型") + private String keyType; + + @ApiModelProperty(value = "字段额外的参数") + private String extra; + + @ApiModelProperty(value = "数据库字段描述") + private String remark; + + @ApiModelProperty(value = "是否必填") + private Boolean notNull; + + @ApiModelProperty(value = "是否在列表显示") + private Boolean listShow; + + @ApiModelProperty(value = "是否表单显示") + private Boolean formShow; + + @ApiModelProperty(value = "表单类型") + private String formType; + + @ApiModelProperty(value = "查询 1:模糊 2:精确") + private String queryType; + + @ApiModelProperty(value = "字典名称") + private String dictName; + + @ApiModelProperty(value = "日期注解") + private String dateAnnotation; + + public ColumnInfo(String tableName, String columnName, Boolean notNull, String columnType, String remark, String keyType, String extra) { + this.tableName = tableName; + this.columnName = columnName; + this.columnType = columnType; + this.keyType = keyType; + this.extra = extra; + this.notNull = notNull; + if(GenUtil.PK.equalsIgnoreCase(keyType) && GenUtil.EXTRA.equalsIgnoreCase(extra)){ + this.notNull = false; + } + this.remark = remark; + this.listShow = true; + this.formShow = true; + } +} diff --git a/wjcy-generator/src/main/java/me/zhengjie/domain/GenConfig.java b/wjcy-generator/src/main/java/me/zhengjie/domain/GenConfig.java new file mode 100644 index 0000000..a2d6706 --- /dev/null +++ b/wjcy-generator/src/main/java/me/zhengjie/domain/GenConfig.java @@ -0,0 +1,78 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * 代码生成配置 + * @author Zheng Jie + * @date 2019-01-03 + */ +@Getter +@Setter +@Entity +@NoArgsConstructor +@Table(name = "code_gen_config") +public class GenConfig implements Serializable { + + public GenConfig(String tableName) { + this.tableName = tableName; + } + + @Id + @Column(name = "config_id") + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotBlank + @ApiModelProperty(value = "表名") + private String tableName; + + @ApiModelProperty(value = "接口名称") + private String apiAlias; + + @NotBlank + @ApiModelProperty(value = "包路径") + private String pack; + + @NotBlank + @ApiModelProperty(value = "模块名") + private String moduleName; + + @NotBlank + @ApiModelProperty(value = "前端文件路径") + private String path; + + @ApiModelProperty(value = "前端文件路径") + private String apiPath; + + @ApiModelProperty(value = "作者") + private String author; + + @ApiModelProperty(value = "表前缀") + private String prefix; + + @ApiModelProperty(value = "是否覆盖") + private Boolean cover = false; +} diff --git a/wjcy-generator/src/main/java/me/zhengjie/domain/vo/TableInfo.java b/wjcy-generator/src/main/java/me/zhengjie/domain/vo/TableInfo.java new file mode 100644 index 0000000..1d3967b --- /dev/null +++ b/wjcy-generator/src/main/java/me/zhengjie/domain/vo/TableInfo.java @@ -0,0 +1,48 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 表的数据信息 + * @author Zheng Jie + * @date 2019-01-02 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class TableInfo { + + /** 表名称 */ + private Object tableName; + + /** 创建日期 */ + private Object createTime; + + /** 数据库引擎 */ + private Object engine; + + /** 编码集 */ + private Object coding; + + /** 备注 */ + private Object remark; + + +} diff --git a/wjcy-generator/src/main/java/me/zhengjie/repository/ColumnInfoRepository.java b/wjcy-generator/src/main/java/me/zhengjie/repository/ColumnInfoRepository.java new file mode 100644 index 0000000..4638be2 --- /dev/null +++ b/wjcy-generator/src/main/java/me/zhengjie/repository/ColumnInfoRepository.java @@ -0,0 +1,34 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.repository; + +import me.zhengjie.domain.ColumnInfo; +import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; + +/** + * @author Zheng Jie + * @date 2019-01-14 + */ +public interface ColumnInfoRepository extends JpaRepository { + + /** + * 查询表信息 + * @param tableName 表格名 + * @return 表信息 + */ + List findByTableNameOrderByIdAsc(String tableName); +} diff --git a/wjcy-generator/src/main/java/me/zhengjie/repository/GenConfigRepository.java b/wjcy-generator/src/main/java/me/zhengjie/repository/GenConfigRepository.java new file mode 100644 index 0000000..18c9a0c --- /dev/null +++ b/wjcy-generator/src/main/java/me/zhengjie/repository/GenConfigRepository.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.repository; + +import me.zhengjie.domain.GenConfig; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * @author Zheng Jie + * @date 2019-01-14 + */ +public interface GenConfigRepository extends JpaRepository { + + /** + * 查询表配置 + * @param tableName 表名 + * @return / + */ + GenConfig findByTableName(String tableName); +} diff --git a/wjcy-generator/src/main/java/me/zhengjie/rest/GenConfigController.java b/wjcy-generator/src/main/java/me/zhengjie/rest/GenConfigController.java new file mode 100644 index 0000000..98ec149 --- /dev/null +++ b/wjcy-generator/src/main/java/me/zhengjie/rest/GenConfigController.java @@ -0,0 +1,51 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.domain.GenConfig; +import me.zhengjie.service.GenConfigService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** + * @author Zheng Jie + * @date 2019-01-14 + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/genConfig") +@Api(tags = "系统:代码生成器配置管理") +public class GenConfigController { + + private final GenConfigService genConfigService; + + @ApiOperation("查询") + @GetMapping(value = "/{tableName}") + public ResponseEntity query(@PathVariable String tableName){ + return new ResponseEntity<>(genConfigService.find(tableName), HttpStatus.OK); + } + + @ApiOperation("修改") + @PutMapping + public ResponseEntity update(@Validated @RequestBody GenConfig genConfig){ + return new ResponseEntity<>(genConfigService.update(genConfig.getTableName(), genConfig),HttpStatus.OK); + } +} diff --git a/wjcy-generator/src/main/java/me/zhengjie/rest/GeneratorController.java b/wjcy-generator/src/main/java/me/zhengjie/rest/GeneratorController.java new file mode 100644 index 0000000..ce6a17d --- /dev/null +++ b/wjcy-generator/src/main/java/me/zhengjie/rest/GeneratorController.java @@ -0,0 +1,107 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.domain.ColumnInfo; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.service.GenConfigService; +import me.zhengjie.service.GeneratorService; +import me.zhengjie.utils.PageUtil; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * @author Zheng Jie + * @date 2019-01-02 + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/generator") +@Api(tags = "系统:代码生成管理") +public class GeneratorController { + + private final GeneratorService generatorService; + private final GenConfigService genConfigService; + + @Value("${generator.enabled}") + private Boolean generatorEnabled; + + @ApiOperation("查询数据库数据") + @GetMapping(value = "/tables/all") + public ResponseEntity queryTables(){ + return new ResponseEntity<>(generatorService.getTables(), HttpStatus.OK); + } + + @ApiOperation("查询数据库数据") + @GetMapping(value = "/tables") + public ResponseEntity queryTables(@RequestParam(defaultValue = "") String name, + @RequestParam(defaultValue = "0")Integer page, + @RequestParam(defaultValue = "10")Integer size){ + int[] startEnd = PageUtil.transToStartEnd(page, size); + return new ResponseEntity<>(generatorService.getTables(name,startEnd), HttpStatus.OK); + } + + @ApiOperation("查询字段数据") + @GetMapping(value = "/columns") + public ResponseEntity queryColumns(@RequestParam String tableName){ + List columnInfos = generatorService.getColumns(tableName); + return new ResponseEntity<>(PageUtil.toPage(columnInfos,columnInfos.size()), HttpStatus.OK); + } + + @ApiOperation("保存字段数据") + @PutMapping + public ResponseEntity save(@RequestBody List columnInfos){ + generatorService.save(columnInfos); + return new ResponseEntity<>(HttpStatus.OK); + } + + @ApiOperation("同步字段数据") + @PostMapping(value = "sync") + public ResponseEntity sync(@RequestBody List tables){ + for (String table : tables) { + generatorService.sync(generatorService.getColumns(table), generatorService.query(table)); + } + return new ResponseEntity<>(HttpStatus.OK); + } + + @ApiOperation("生成代码") + @PostMapping(value = "/{tableName}/{type}") + public ResponseEntity generator(@PathVariable String tableName, @PathVariable Integer type, HttpServletRequest request, HttpServletResponse response){ + if(!generatorEnabled && type == 0){ + throw new BadRequestException("此环境不允许生成代码,请选择预览或者下载查看!"); + } + switch (type){ + // 生成代码 + case 0: generatorService.generator(genConfigService.find(tableName), generatorService.getColumns(tableName)); + break; + // 预览 + case 1: return generatorService.preview(genConfigService.find(tableName), generatorService.getColumns(tableName)); + // 打包 + case 2: generatorService.download(genConfigService.find(tableName), generatorService.getColumns(tableName), request, response); + break; + default: throw new BadRequestException("没有这个选项"); + } + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/wjcy-generator/src/main/java/me/zhengjie/service/GenConfigService.java b/wjcy-generator/src/main/java/me/zhengjie/service/GenConfigService.java new file mode 100644 index 0000000..b5711f4 --- /dev/null +++ b/wjcy-generator/src/main/java/me/zhengjie/service/GenConfigService.java @@ -0,0 +1,40 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.service; + +import me.zhengjie.domain.GenConfig; + +/** + * @author Zheng Jie + * @date 2019-01-14 + */ +public interface GenConfigService { + + /** + * 查询表配置 + * @param tableName 表名 + * @return 表配置 + */ + GenConfig find(String tableName); + + /** + * 更新表配置 + * @param tableName 表名 + * @param genConfig 表配置 + * @return 表配置 + */ + GenConfig update(String tableName, GenConfig genConfig); +} diff --git a/wjcy-generator/src/main/java/me/zhengjie/service/GeneratorService.java b/wjcy-generator/src/main/java/me/zhengjie/service/GeneratorService.java new file mode 100644 index 0000000..b5a1e0a --- /dev/null +++ b/wjcy-generator/src/main/java/me/zhengjie/service/GeneratorService.java @@ -0,0 +1,96 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.service; + +import me.zhengjie.domain.GenConfig; +import me.zhengjie.domain.ColumnInfo; +import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.annotation.Async; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * @author Zheng Jie + * @date 2019-01-02 + */ +public interface GeneratorService { + + /** + * 查询数据库元数据 + * @param name 表名 + * @param startEnd 分页参数 + * @return / + */ + Object getTables(String name, int[] startEnd); + + /** + * 得到数据表的元数据 + * @param name 表名 + * @return / + */ + List getColumns(String name); + + /** + * 同步表数据 + * @param columnInfos / + * @param columnInfoList / + */ + void sync(List columnInfos, List columnInfoList); + + /** + * 保持数据 + * @param columnInfos / + */ + void save(List columnInfos); + + /** + * 获取所有table + * @return / + */ + Object getTables(); + + /** + * 代码生成 + * @param genConfig 配置信息 + * @param columns 字段信息 + */ + void generator(GenConfig genConfig, List columns); + + /** + * 预览 + * @param genConfig 配置信息 + * @param columns 字段信息 + * @return / + */ + ResponseEntity preview(GenConfig genConfig, List columns); + + /** + * 打包下载 + * @param genConfig 配置信息 + * @param columns 字段信息 + * @param request / + * @param response / + */ + void download(GenConfig genConfig, List columns, HttpServletRequest request, HttpServletResponse response); + + /** + * 查询数据库的表字段数据数据 + * @param table / + * @return / + */ + List query(String table); +} diff --git a/wjcy-generator/src/main/java/me/zhengjie/service/impl/GenConfigServiceImpl.java b/wjcy-generator/src/main/java/me/zhengjie/service/impl/GenConfigServiceImpl.java new file mode 100644 index 0000000..bc2d061 --- /dev/null +++ b/wjcy-generator/src/main/java/me/zhengjie/service/impl/GenConfigServiceImpl.java @@ -0,0 +1,67 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.service.impl; + +import lombok.RequiredArgsConstructor; +import me.zhengjie.domain.GenConfig; +import me.zhengjie.repository.GenConfigRepository; +import me.zhengjie.service.GenConfigService; +import me.zhengjie.utils.StringUtils; +import org.springframework.stereotype.Service; +import java.io.File; + +/** + * @author Zheng Jie + * @date 2019-01-14 + */ +@Service +@RequiredArgsConstructor +public class GenConfigServiceImpl implements GenConfigService { + + private final GenConfigRepository genConfigRepository; + + @Override + public GenConfig find(String tableName) { + GenConfig genConfig = genConfigRepository.findByTableName(tableName); + if(genConfig == null){ + return new GenConfig(tableName); + } + return genConfig; + } + + @Override + public GenConfig update(String tableName, GenConfig genConfig) { + String separator = File.separator; + String[] paths; + String symbol = "\\"; + if (symbol.equals(separator)) { + paths = genConfig.getPath().split("\\\\"); + } else { + paths = genConfig.getPath().split(File.separator); + } + StringBuilder api = new StringBuilder(); + for (String path : paths) { + api.append(path); + api.append(separator); + if ("src".equals(path)) { + api.append("api"); + break; + } + } + genConfig.setApiPath(api.toString()); + return genConfigRepository.save(genConfig); + } +} diff --git a/wjcy-generator/src/main/java/me/zhengjie/service/impl/GeneratorServiceImpl.java b/wjcy-generator/src/main/java/me/zhengjie/service/impl/GeneratorServiceImpl.java new file mode 100644 index 0000000..1b1803b --- /dev/null +++ b/wjcy-generator/src/main/java/me/zhengjie/service/impl/GeneratorServiceImpl.java @@ -0,0 +1,203 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.ZipUtil; +import lombok.RequiredArgsConstructor; +import me.zhengjie.domain.GenConfig; +import me.zhengjie.domain.ColumnInfo; +import me.zhengjie.domain.vo.TableInfo; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.repository.ColumnInfoRepository; +import me.zhengjie.service.GeneratorService; +import me.zhengjie.utils.FileUtil; +import me.zhengjie.utils.GenUtil; +import me.zhengjie.utils.PageUtil; +import me.zhengjie.utils.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.Query; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author Zheng Jie + * @date 2019-01-02 + */ +@Service +@RequiredArgsConstructor +public class GeneratorServiceImpl implements GeneratorService { + private static final Logger log = LoggerFactory.getLogger(GeneratorServiceImpl.class); + @PersistenceContext + private EntityManager em; + + private final ColumnInfoRepository columnInfoRepository; + + @Override + public Object getTables() { + // 使用预编译防止sql注入 + String sql = "select table_name ,create_time , engine, table_collation, table_comment from information_schema.tables " + + "where table_schema = (select database()) " + + "order by create_time desc"; + Query query = em.createNativeQuery(sql); + return query.getResultList(); + } + + @Override + public Object getTables(String name, int[] startEnd) { + // 使用预编译防止sql注入 + String sql = "select table_name ,create_time , engine, table_collation, table_comment from information_schema.tables " + + "where table_schema = (select database()) " + + "and table_name like ? order by create_time desc"; + Query query = em.createNativeQuery(sql); + query.setFirstResult(startEnd[0]); + query.setMaxResults(startEnd[1] - startEnd[0]); + query.setParameter(1, StringUtils.isNotBlank(name) ? ("%" + name + "%") : "%%"); + List result = query.getResultList(); + List tableInfos = new ArrayList<>(); + for (Object obj : result) { + Object[] arr = (Object[]) obj; + tableInfos.add(new TableInfo(arr[0], arr[1], arr[2], arr[3], ObjectUtil.isNotEmpty(arr[4]) ? arr[4] : "-")); + } + Query query1 = em.createNativeQuery("SELECT COUNT(*) from information_schema.tables where table_schema = (select database())"); + Object totalElements = query1.getSingleResult(); + return PageUtil.toPage(tableInfos, totalElements); + } + + @Override + public List getColumns(String tableName) { + List columnInfos = columnInfoRepository.findByTableNameOrderByIdAsc(tableName); + if (CollectionUtil.isNotEmpty(columnInfos)) { + return columnInfos; + } else { + columnInfos = query(tableName); + return columnInfoRepository.saveAll(columnInfos); + } + } + + @Override + public List query(String tableName) { + // 使用预编译防止sql注入 + String sql = "select column_name, is_nullable, data_type, column_comment, column_key, extra from information_schema.columns " + + "where table_name = ? and table_schema = (select database()) order by ordinal_position"; + Query query = em.createNativeQuery(sql); + query.setParameter(1, tableName); + List result = query.getResultList(); + List columnInfos = new ArrayList<>(); + for (Object obj : result) { + Object[] arr = (Object[]) obj; + columnInfos.add( + new ColumnInfo( + tableName, + arr[0].toString(), + "NO".equals(arr[1]), + arr[2].toString(), + ObjectUtil.isNotNull(arr[3]) ? arr[3].toString() : null, + ObjectUtil.isNotNull(arr[4]) ? arr[4].toString() : null, + ObjectUtil.isNotNull(arr[5]) ? arr[5].toString() : null) + ); + } + return columnInfos; + } + + @Override + public void sync(List columnInfos, List columnInfoList) { + // 第一种情况,数据库类字段改变或者新增字段 + for (ColumnInfo columnInfo : columnInfoList) { + // 根据字段名称查找 + List columns = columnInfos.stream().filter(c -> c.getColumnName().equals(columnInfo.getColumnName())).collect(Collectors.toList()); + // 如果能找到,就修改部分可能被字段 + if (CollectionUtil.isNotEmpty(columns)) { + ColumnInfo column = columns.get(0); + column.setColumnType(columnInfo.getColumnType()); + column.setExtra(columnInfo.getExtra()); + column.setKeyType(columnInfo.getKeyType()); + if (StringUtils.isBlank(column.getRemark())) { + column.setRemark(columnInfo.getRemark()); + } + columnInfoRepository.save(column); + } else { + // 如果找不到,则保存新字段信息 + columnInfoRepository.save(columnInfo); + } + } + // 第二种情况,数据库字段删除了 + for (ColumnInfo columnInfo : columnInfos) { + // 根据字段名称查找 + List columns = columnInfoList.stream().filter(c -> c.getColumnName().equals(columnInfo.getColumnName())).collect(Collectors.toList()); + // 如果找不到,就代表字段被删除了,则需要删除该字段 + if (CollectionUtil.isEmpty(columns)) { + columnInfoRepository.delete(columnInfo); + } + } + } + + @Override + public void save(List columnInfos) { + columnInfoRepository.saveAll(columnInfos); + } + + @Override + public void generator(GenConfig genConfig, List columns) { + if (genConfig.getId() == null) { + throw new BadRequestException("请先配置生成器"); + } + try { + GenUtil.generatorCode(columns, genConfig); + } catch (IOException e) { + log.error(e.getMessage(), e); + throw new BadRequestException("生成失败,请手动处理已生成的文件"); + } + } + + @Override + public ResponseEntity preview(GenConfig genConfig, List columns) { + if (genConfig.getId() == null) { + throw new BadRequestException("请先配置生成器"); + } + List> genList = GenUtil.preview(columns, genConfig); + return new ResponseEntity<>(genList, HttpStatus.OK); + } + + @Override + public void download(GenConfig genConfig, List columns, HttpServletRequest request, HttpServletResponse response) { + if (genConfig.getId() == null) { + throw new BadRequestException("请先配置生成器"); + } + try { + File file = new File(GenUtil.download(columns, genConfig)); + String zipPath = file.getPath() + ".zip"; + ZipUtil.zip(file.getPath(), zipPath); + FileUtil.downloadFile(request, response, new File(zipPath), true); + } catch (IOException e) { + throw new BadRequestException("打包失败"); + } + } +} diff --git a/wjcy-generator/src/main/java/me/zhengjie/utils/ColUtil.java b/wjcy-generator/src/main/java/me/zhengjie/utils/ColUtil.java new file mode 100644 index 0000000..b5fcd6b --- /dev/null +++ b/wjcy-generator/src/main/java/me/zhengjie/utils/ColUtil.java @@ -0,0 +1,54 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils; + +import org.apache.commons.configuration.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * sql字段转java + * + * @author Zheng Jie + * @date 2019-01-03 + */ +public class ColUtil { + private static final Logger log = LoggerFactory.getLogger(ColUtil.class); + + /** + * 转换mysql数据类型为java数据类型 + * + * @param type 数据库字段类型 + * @return String + */ + static String cloToJava(String type) { + Configuration config = getConfig(); + assert config != null; + return config.getString(type, "unknowType"); + } + + /** + * 获取配置信息 + */ + public static PropertiesConfiguration getConfig() { + try { + return new PropertiesConfiguration("generator.properties"); + } catch (ConfigurationException e) { + log.error(e.getMessage(), e); + } + return null; + } +} diff --git a/wjcy-generator/src/main/java/me/zhengjie/utils/GenUtil.java b/wjcy-generator/src/main/java/me/zhengjie/utils/GenUtil.java new file mode 100644 index 0000000..566b6d8 --- /dev/null +++ b/wjcy-generator/src/main/java/me/zhengjie/utils/GenUtil.java @@ -0,0 +1,420 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.utils; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.template.*; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.domain.GenConfig; +import me.zhengjie.domain.ColumnInfo; +import org.springframework.util.ObjectUtils; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.time.LocalDate; +import java.util.*; + +import static me.zhengjie.utils.FileUtil.SYS_TEM_DIR; + +/** + * 代码生成 + * + * @author Zheng Jie + * @date 2019-01-02 + */ +@Slf4j +@SuppressWarnings({"unchecked", "all"}) +public class GenUtil { + + private static final String TIMESTAMP = "Timestamp"; + + private static final String BIGDECIMAL = "BigDecimal"; + + public static final String PK = "PRI"; + + public static final String EXTRA = "auto_increment"; + + /** + * 获取后端代码模板名称 + * + * @return List + */ + private static List getAdminTemplateNames() { + List templateNames = new ArrayList<>(); + templateNames.add("Entity"); + templateNames.add("Dto"); + templateNames.add("Mapper"); + templateNames.add("Controller"); + templateNames.add("QueryCriteria"); + templateNames.add("Service"); + templateNames.add("ServiceImpl"); + templateNames.add("Repository"); + return templateNames; + } + + /** + * 获取前端代码模板名称 + * + * @return List + */ + private static List getFrontTemplateNames() { + List templateNames = new ArrayList<>(); + templateNames.add("index"); + templateNames.add("api"); + return templateNames; + } + + public static List> preview(List columns, GenConfig genConfig) { + Map genMap = getGenMap(columns, genConfig); + List> genList = new ArrayList<>(); + // 获取后端模版 + List templates = getAdminTemplateNames(); + TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH)); + for (String templateName : templates) { + Map map = new HashMap<>(1); + Template template = engine.getTemplate("generator/admin/" + templateName + ".ftl"); + map.put("content", template.render(genMap)); + map.put("name", templateName); + genList.add(map); + } + // 获取前端模版 + templates = getFrontTemplateNames(); + for (String templateName : templates) { + Map map = new HashMap<>(1); + Template template = engine.getTemplate("generator/front/" + templateName + ".ftl"); + map.put(templateName, template.render(genMap)); + map.put("content", template.render(genMap)); + map.put("name", templateName); + genList.add(map); + } + return genList; + } + + public static String download(List columns, GenConfig genConfig) throws IOException { + // 拼接的路径:/tmpeladmin-gen-temp/,这个路径在Linux下需要root用户才有权限创建,非root用户会权限错误而失败,更改为: /tmp/eladmin-gen-temp/ + // String tempPath =SYS_TEM_DIR + "eladmin-gen-temp" + File.separator + genConfig.getTableName() + File.separator; + String tempPath = SYS_TEM_DIR + "eladmin-gen-temp" + File.separator + genConfig.getTableName() + File.separator; + Map genMap = getGenMap(columns, genConfig); + TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH)); + // 生成后端代码 + List templates = getAdminTemplateNames(); + for (String templateName : templates) { + Template template = engine.getTemplate("generator/admin/" + templateName + ".ftl"); + String filePath = getAdminFilePath(templateName, genConfig, genMap.get("className").toString(), tempPath + "eladmin" + File.separator); + assert filePath != null; + File file = new File(filePath); + // 如果非覆盖生成 + if (!genConfig.getCover() && FileUtil.exist(file)) { + continue; + } + // 生成代码 + genFile(file, template, genMap); + } + // 生成前端代码 + templates = getFrontTemplateNames(); + for (String templateName : templates) { + Template template = engine.getTemplate("generator/front/" + templateName + ".ftl"); + String path = tempPath + "eladmin-web" + File.separator; + String apiPath = path + "src" + File.separator + "api" + File.separator; + String srcPath = path + "src" + File.separator + "views" + File.separator + genMap.get("changeClassName").toString() + File.separator; + String filePath = getFrontFilePath(templateName, apiPath, srcPath, genMap.get("changeClassName").toString()); + assert filePath != null; + File file = new File(filePath); + // 如果非覆盖生成 + if (!genConfig.getCover() && FileUtil.exist(file)) { + continue; + } + // 生成代码 + genFile(file, template, genMap); + } + return tempPath; + } + + public static void generatorCode(List columnInfos, GenConfig genConfig) throws IOException { + Map genMap = getGenMap(columnInfos, genConfig); + TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH)); + // 生成后端代码 + List templates = getAdminTemplateNames(); + for (String templateName : templates) { + Template template = engine.getTemplate("generator/admin/" + templateName + ".ftl"); + String rootPath = System.getProperty("user.dir"); + String filePath = getAdminFilePath(templateName, genConfig, genMap.get("className").toString(), rootPath); + + assert filePath != null; + File file = new File(filePath); + + // 如果非覆盖生成 + if (!genConfig.getCover() && FileUtil.exist(file)) { + continue; + } + // 生成代码 + genFile(file, template, genMap); + } + + // 生成前端代码 + templates = getFrontTemplateNames(); + for (String templateName : templates) { + Template template = engine.getTemplate("generator/front/" + templateName + ".ftl"); + String filePath = getFrontFilePath(templateName, genConfig.getApiPath(), genConfig.getPath(), genMap.get("changeClassName").toString()); + + assert filePath != null; + File file = new File(filePath); + + // 如果非覆盖生成 + if (!genConfig.getCover() && FileUtil.exist(file)) { + continue; + } + // 生成代码 + genFile(file, template, genMap); + } + } + + // 获取模版数据 + private static Map getGenMap(List columnInfos, GenConfig genConfig) { + // 存储模版字段数据 + Map genMap = new HashMap<>(16); + // 接口别名 + genMap.put("apiAlias", genConfig.getApiAlias()); + // 包名称 + genMap.put("package", genConfig.getPack()); + // 模块名称 + genMap.put("moduleName", genConfig.getModuleName()); + // 作者 + genMap.put("author", genConfig.getAuthor()); + // 创建日期 + genMap.put("date", LocalDate.now().toString()); + // 表名 + genMap.put("tableName", genConfig.getTableName()); + // 大写开头的类名 + String className = StringUtils.toCapitalizeCamelCase(genConfig.getTableName()); + // 小写开头的类名 + String changeClassName = StringUtils.toCamelCase(genConfig.getTableName()); + // 判断是否去除表前缀 + if (StringUtils.isNotEmpty(genConfig.getPrefix())) { + className = StringUtils.toCapitalizeCamelCase(StrUtil.removePrefix(genConfig.getTableName(), genConfig.getPrefix())); + changeClassName = StringUtils.toCamelCase(StrUtil.removePrefix(genConfig.getTableName(), genConfig.getPrefix())); + } + // 保存类名 + genMap.put("className", className); + // 保存小写开头的类名 + genMap.put("changeClassName", changeClassName); + // 存在 Timestamp 字段 + genMap.put("hasTimestamp", false); + // 查询类中存在 Timestamp 字段 + genMap.put("queryHasTimestamp", false); + // 存在 BigDecimal 字段 + genMap.put("hasBigDecimal", false); + // 查询类中存在 BigDecimal 字段 + genMap.put("queryHasBigDecimal", false); + // 是否需要创建查询 + genMap.put("hasQuery", false); + // 自增主键 + genMap.put("auto", false); + // 存在字典 + genMap.put("hasDict", false); + // 存在日期注解 + genMap.put("hasDateAnnotation", false); + // 保存字段信息 + List> columns = new ArrayList<>(); + // 保存查询字段的信息 + List> queryColumns = new ArrayList<>(); + // 存储字典信息 + List dicts = new ArrayList<>(); + // 存储 between 信息 + List> betweens = new ArrayList<>(); + // 存储不为空的字段信息 + List> isNotNullColumns = new ArrayList<>(); + + for (ColumnInfo column : columnInfos) { + Map listMap = new HashMap<>(16); + // 字段描述 + listMap.put("remark", column.getRemark()); + // 字段类型 + listMap.put("columnKey", column.getKeyType()); + // 主键类型 + String colType = ColUtil.cloToJava(column.getColumnType()); + // 小写开头的字段名 + String changeColumnName = StringUtils.toCamelCase(column.getColumnName()); + // 大写开头的字段名 + String capitalColumnName = StringUtils.toCapitalizeCamelCase(column.getColumnName()); + if (PK.equals(column.getKeyType())) { + // 存储主键类型 + genMap.put("pkColumnType", colType); + // 存储小写开头的字段名 + genMap.put("pkChangeColName", changeColumnName); + // 存储大写开头的字段名 + genMap.put("pkCapitalColName", capitalColumnName); + } + // 是否存在 Timestamp 类型的字段 + if (TIMESTAMP.equals(colType)) { + genMap.put("hasTimestamp", true); + } + // 是否存在 BigDecimal 类型的字段 + if (BIGDECIMAL.equals(colType)) { + genMap.put("hasBigDecimal", true); + } + // 主键是否自增 + if (EXTRA.equals(column.getExtra())) { + genMap.put("auto", true); + } + // 主键存在字典 + if (StringUtils.isNotBlank(column.getDictName())) { + genMap.put("hasDict", true); + dicts.add(column.getDictName()); + } + + // 存储字段类型 + listMap.put("columnType", colType); + // 存储字原始段名称 + listMap.put("columnName", column.getColumnName()); + // 不为空 + listMap.put("istNotNull", column.getNotNull()); + // 字段列表显示 + listMap.put("columnShow", column.getListShow()); + // 表单显示 + listMap.put("formShow", column.getFormShow()); + // 表单组件类型 + listMap.put("formType", StringUtils.isNotBlank(column.getFormType()) ? column.getFormType() : "Input"); + // 小写开头的字段名称 + listMap.put("changeColumnName", changeColumnName); + //大写开头的字段名称 + listMap.put("capitalColumnName", capitalColumnName); + // 字典名称 + listMap.put("dictName", column.getDictName()); + // 日期注解 + listMap.put("dateAnnotation", column.getDateAnnotation()); + if (StringUtils.isNotBlank(column.getDateAnnotation())) { + genMap.put("hasDateAnnotation", true); + } + // 添加非空字段信息 + if (column.getNotNull()) { + isNotNullColumns.add(listMap); + } + // 判断是否有查询,如有则把查询的字段set进columnQuery + if (!StringUtils.isBlank(column.getQueryType())) { + // 查询类型 + listMap.put("queryType", column.getQueryType()); + // 是否存在查询 + genMap.put("hasQuery", true); + if (TIMESTAMP.equals(colType)) { + // 查询中存储 Timestamp 类型 + genMap.put("queryHasTimestamp", true); + } + if (BIGDECIMAL.equals(colType)) { + // 查询中存储 BigDecimal 类型 + genMap.put("queryHasBigDecimal", true); + } + if ("between".equalsIgnoreCase(column.getQueryType())) { + betweens.add(listMap); + } else { + // 添加到查询列表中 + queryColumns.add(listMap); + } + } + // 添加到字段列表中 + columns.add(listMap); + } + // 保存字段列表 + genMap.put("columns", columns); + // 保存查询列表 + genMap.put("queryColumns", queryColumns); + // 保存字段列表 + genMap.put("dicts", dicts); + // 保存查询列表 + genMap.put("betweens", betweens); + // 保存非空字段信息 + genMap.put("isNotNullColumns", isNotNullColumns); + return genMap; + } + + /** + * 定义后端文件路径以及名称 + */ + private static String getAdminFilePath(String templateName, GenConfig genConfig, String className, String rootPath) { + String projectPath = rootPath + File.separator + genConfig.getModuleName(); + String packagePath = projectPath + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator; + if (!ObjectUtils.isEmpty(genConfig.getPack())) { + packagePath += genConfig.getPack().replace(".", File.separator) + File.separator; + } + + if ("Entity".equals(templateName)) { + return packagePath + "domain" + File.separator + className + ".java"; + } + + if ("Controller".equals(templateName)) { + return packagePath + "rest" + File.separator + className + "Controller.java"; + } + + if ("Service".equals(templateName)) { + return packagePath + "service" + File.separator + className + "Service.java"; + } + + if ("ServiceImpl".equals(templateName)) { + return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java"; + } + + if ("Dto".equals(templateName)) { + return packagePath + "service" + File.separator + "dto" + File.separator + className + "Dto.java"; + } + + if ("QueryCriteria".equals(templateName)) { + return packagePath + "service" + File.separator + "dto" + File.separator + className + "QueryCriteria.java"; + } + + if ("Mapper".equals(templateName)) { + return packagePath + "service" + File.separator + "mapstruct" + File.separator + className + "Mapper.java"; + } + + if ("Repository".equals(templateName)) { + return packagePath + "repository" + File.separator + className + "Repository.java"; + } + + return null; + } + + /** + * 定义前端文件路径以及名称 + */ + private static String getFrontFilePath(String templateName, String apiPath, String path, String apiName) { + + if ("api".equals(templateName)) { + return apiPath + File.separator + apiName + ".js"; + } + + if ("index".equals(templateName)) { + return path + File.separator + "index.vue"; + } + + return null; + } + + private static void genFile(File file, Template template, Map map) throws IOException { + // 生成目标文件 + Writer writer = null; + try { + FileUtil.touch(file); + writer = new FileWriter(file); + template.render(map, writer); + } catch (TemplateException | IOException e) { + throw new RuntimeException(e); + } finally { + assert writer != null; + writer.close(); + } + } +} diff --git a/wjcy-logging/pom.xml b/wjcy-logging/pom.xml new file mode 100644 index 0000000..98d6734 --- /dev/null +++ b/wjcy-logging/pom.xml @@ -0,0 +1,22 @@ + + + + wjcy + me.zhengjie + 1.0 + + 4.0.0 + + wjcy-logging + 日志模块 + + + + me.zhengjie + wjcy-common + 1.0 + + + \ No newline at end of file diff --git a/wjcy-logging/src/main/java/me/zhengjie/annotation/Log.java b/wjcy-logging/src/main/java/me/zhengjie/annotation/Log.java new file mode 100644 index 0000000..ac0a0cd --- /dev/null +++ b/wjcy-logging/src/main/java/me/zhengjie/annotation/Log.java @@ -0,0 +1,55 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.annotation; + +import me.zhengjie.annotation.type.LogActionType; +import me.zhengjie.annotation.type.LogDaoType; +import me.zhengjie.annotation.type.LogGetIdType; +import me.zhengjie.annotation.type.LogGetValueType; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Zheng Jie + * @date 2018-11-24 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Log { + String value() default ""; + + String[] daoNames() default {}; + + LogGetIdType[] idTypes() default {LogGetIdType.ID}; + + LogGetValueType[] valuesTypes() default {LogGetValueType.ID}; + + LogDaoType daoType() default LogDaoType.MyBATISPLUS; + + boolean trueList() default false; + + /** + * 是否启用 + * + * @return + */ + boolean enable() default true; + + LogActionType type() default LogActionType.SELECT; +} diff --git a/wjcy-logging/src/main/java/me/zhengjie/annotation/type/LogActionType.java b/wjcy-logging/src/main/java/me/zhengjie/annotation/type/LogActionType.java new file mode 100644 index 0000000..e99d671 --- /dev/null +++ b/wjcy-logging/src/main/java/me/zhengjie/annotation/type/LogActionType.java @@ -0,0 +1,34 @@ +package me.zhengjie.annotation.type; + +/** + *

+ * 日志类型 + *

+ * + * @Author xx + * @Date 2021/7/22 + **/ +public enum LogActionType { + /** + * 增删改查 + */ + ADD("新增"), + SELECT("查询"), + UPDATE("更新"), + DELETE("删除"), + LOGIN("登录"), + EXPORT("导出"); + private String value; + + LogActionType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/wjcy-logging/src/main/java/me/zhengjie/annotation/type/LogDaoType.java b/wjcy-logging/src/main/java/me/zhengjie/annotation/type/LogDaoType.java new file mode 100644 index 0000000..2c96f80 --- /dev/null +++ b/wjcy-logging/src/main/java/me/zhengjie/annotation/type/LogDaoType.java @@ -0,0 +1,30 @@ +package me.zhengjie.annotation.type; + +/** + *

+ *日志使用dao类型 + *

+ * + * @Author xx + * @Date 2021/7/22 + **/ +public enum LogDaoType { + /** + * 增删改查 + */ + MyBATISPLUS("myabtisPlus"), + SPRINGDATAJPA("springDataJpa"); + private String value; + + LogDaoType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/wjcy-logging/src/main/java/me/zhengjie/annotation/type/LogGetIdType.java b/wjcy-logging/src/main/java/me/zhengjie/annotation/type/LogGetIdType.java new file mode 100644 index 0000000..cb4a005 --- /dev/null +++ b/wjcy-logging/src/main/java/me/zhengjie/annotation/type/LogGetIdType.java @@ -0,0 +1,36 @@ +package me.zhengjie.annotation.type; + +/** + *

+ * 日志获取修改前信息使用id类型 具体有别的在具体添加 + *

+ * + * @Author xx + * @Date 2021/7/22 + **/ +public enum LogGetIdType { + + /** ID */ + ID("id"), + /** IDS */ + IDS("ids"), + /** MEMBER_ID */ + MEMBER_ID("memberId"), + /** AUTHMEMBER_ID */ + AUTHMEMBER_ID("authMemberId"), + /** ROOM_Id */ + ROOM_Id("roomId"); + private String value; + + LogGetIdType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/wjcy-logging/src/main/java/me/zhengjie/annotation/type/LogGetValueType.java b/wjcy-logging/src/main/java/me/zhengjie/annotation/type/LogGetValueType.java new file mode 100644 index 0000000..1024cbb --- /dev/null +++ b/wjcy-logging/src/main/java/me/zhengjie/annotation/type/LogGetValueType.java @@ -0,0 +1,32 @@ +package me.zhengjie.annotation.type; + +/** + *

+ * 日志获取修改前信息使用id对应值 具体有别的在具体添加 + *

+ * + * @Author xx + * @Date 2021/7/22 + **/ +public enum LogGetValueType { + + /** ID */ + ID("id"), + /** MEMBER_ID */ + MEMBER_ID("memberId"), + /** ROOM_ID */ + ROOM_ID("roomId"); + private String value; + + LogGetValueType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/wjcy-logging/src/main/java/me/zhengjie/aspect/LogAspect.java b/wjcy-logging/src/main/java/me/zhengjie/aspect/LogAspect.java new file mode 100644 index 0000000..01bce24 --- /dev/null +++ b/wjcy-logging/src/main/java/me/zhengjie/aspect/LogAspect.java @@ -0,0 +1,98 @@ +///* +// * Copyright 2019-2020 Zheng Jie +// * +// * Licensed under the Apache License, Version 2.0 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +//package me.zhengjie.aspect; +// +//import lombok.extern.slf4j.Slf4j; +//import me.zhengjie.domain.Log; +//import me.zhengjie.service.LogService; +//import me.zhengjie.utils.RequestHolder; +//import me.zhengjie.utils.SecurityUtils; +//import me.zhengjie.utils.StringUtils; +//import me.zhengjie.utils.ThrowableUtil; +//import org.aspectj.lang.JoinPoint; +//import org.aspectj.lang.ProceedingJoinPoint; +//import org.aspectj.lang.annotation.AfterThrowing; +//import org.aspectj.lang.annotation.Around; +//import org.aspectj.lang.annotation.Aspect; +//import org.aspectj.lang.annotation.Pointcut; +//import org.springframework.stereotype.Component; +//import javax.servlet.http.HttpServletRequest; +// +///** +// * @author Zheng Jie +// * @date 2018-11-24 +// */ +//@Component +//@Aspect +//@Slf4j +//public class LogAspect { +// +// private final LogService logService; +// +// ThreadLocal currentTime = new ThreadLocal<>(); +// +// public LogAspect(LogService logService) { +// this.logService = logService; +// } +// +// /** +// * 配置切入点 +// */ +// @Pointcut("@annotation(me.zhengjie.annotation.Log)") +// public void logPointcut() { +// // 该方法无方法体,主要为了让同类中其他方法使用此切入点 +// } +// +// /** +// * 配置环绕通知,使用在方法logPointcut()上注册的切入点 +// * +// * @param joinPoint join point for advice +// */ +// @Around("logPointcut()") +// public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { +// Object result; +// currentTime.set(System.currentTimeMillis()); +// result = joinPoint.proceed(); +// Log log = new Log("INFO",System.currentTimeMillis() - currentTime.get()); +// currentTime.remove(); +// HttpServletRequest request = RequestHolder.getHttpServletRequest(); +// logService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request),joinPoint, log); +// return result; +// } +// +// /** +// * 配置异常通知 +// * +// * @param joinPoint join point for advice +// * @param e exception +// */ +// @AfterThrowing(pointcut = "logPointcut()", throwing = "e") +// public void logAfterThrowing(JoinPoint joinPoint, Throwable e) { +// Log log = new Log("ERROR",System.currentTimeMillis() - currentTime.get()); +// currentTime.remove(); +// log.setExceptionDetail(ThrowableUtil.getStackTrace(e).getBytes()); +// HttpServletRequest request = RequestHolder.getHttpServletRequest(); +// logService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request), (ProceedingJoinPoint)joinPoint, log); +// } +// +// public String getUsername() { +// try { +// return SecurityUtils.getCurrentUsername(); +// }catch (Exception e){ +// return ""; +// } +// } +//} diff --git a/wjcy-logging/src/main/java/me/zhengjie/domain/Log.java b/wjcy-logging/src/main/java/me/zhengjie/domain/Log.java new file mode 100644 index 0000000..baed7df --- /dev/null +++ b/wjcy-logging/src/main/java/me/zhengjie/domain/Log.java @@ -0,0 +1,95 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.domain; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.CreationTimestamp; +import javax.persistence.*; +import java.io.Serializable; +import java.sql.Timestamp; + + +/** + * @author Zheng Jie + * @date 2018-11-24 + */ +@Entity +@Getter +@Setter +@Table(name = "sys_log") +@NoArgsConstructor +public class Log implements Serializable { + + @Id + @Column(name = "log_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + /** 操作用户 */ + private String username; + + /** 描述 */ + private String description; + + /** 方法名 */ + private String method; + + /** 参数 */ + private String params; + + /** 日志类型 */ + private String logType; + + /** 请求ip */ + private String requestIp; + + /** 地址 */ + private String address; + + /** 浏览器 */ + private String browser; + + /** 请求耗时 */ + private Long time; + + /** 异常详细 */ + private String exceptionDetail; + + /** 创建日期 */ + @CreationTimestamp + private Timestamp createTime; + + /** 用户类型 */ + private Integer type; + + /** 日志记录 */ + private String platParams; + + @Transient + private Boolean trueList; + + public Log(String logType, Long time) { + this.logType = logType; + this.time = time; + } + public Log(String logType, Long time, Integer type) { + this.logType = logType; + this.time = time; + this.type = type; + } +} diff --git a/wjcy-logging/src/main/java/me/zhengjie/enums/LogTypeEnum.java b/wjcy-logging/src/main/java/me/zhengjie/enums/LogTypeEnum.java new file mode 100644 index 0000000..eb87f89 --- /dev/null +++ b/wjcy-logging/src/main/java/me/zhengjie/enums/LogTypeEnum.java @@ -0,0 +1,33 @@ +package me.zhengjie.enums; +/** + *

+ * 日志类型 + *

+ * + * @Author xx + * @Date 2021/7/22 + **/ +public enum LogTypeEnum { + /** + * 是否展示详情类型 + * 1 修改 + * 0 不展示 + * 2 新增 + */ + + NO_PLAT_PARAMS(0), + SHOW_PLAT_PARAMS(1), + SHOW_ADD_PARAMS(2), + SHOW_LOGIN_PARAMS(3); + + private final Integer value; + + private LogTypeEnum(Integer value) { + this.value = value; + } + + + public Integer value() { + return this.value; + } +} diff --git a/wjcy-logging/src/main/java/me/zhengjie/repository/LogRepository.java b/wjcy-logging/src/main/java/me/zhengjie/repository/LogRepository.java new file mode 100644 index 0000000..0414b3e --- /dev/null +++ b/wjcy-logging/src/main/java/me/zhengjie/repository/LogRepository.java @@ -0,0 +1,49 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.repository; + +import me.zhengjie.domain.Log; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * @author Zheng Jie + * @date 2018-11-24 + */ +@Repository +public interface LogRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 根据日志类型删除信息 + * @param logType 日志类型 + */ + @Modifying + @Query(value = "delete from sys_log where log_type = ?1", nativeQuery = true) + void deleteByLogType(String logType); + + /** + * 根据日志类型和显示类型删除信息 + * @param logType 日志类型 + */ + @Modifying + @Query(value = " delete from sys_log where log_type = ?1 and type in ?2",nativeQuery = true) + void deleteByLogTypeAndTypeContains(String logType, List typeList); +} diff --git a/wjcy-logging/src/main/java/me/zhengjie/rest/LogController.java b/wjcy-logging/src/main/java/me/zhengjie/rest/LogController.java new file mode 100644 index 0000000..23d27db --- /dev/null +++ b/wjcy-logging/src/main/java/me/zhengjie/rest/LogController.java @@ -0,0 +1,157 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.Log; +import me.zhengjie.dto.Dto; +import me.zhengjie.enums.LogTypeEnum; +import me.zhengjie.service.LogService; +import me.zhengjie.service.dto.LogQueryCriteria; +import me.zhengjie.utils.SecurityUtils; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Arrays; + +/** + * @author Zheng Jie + * @date 2018-11-24 + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/logs") +@Api(tags = "系统:日志管理") +public class LogController { + + private final LogService logService; + + @Log("导出操作日志数据") + @ApiOperation("导出操作日志数据") + @GetMapping(value = "/queryLog/download") + @PreAuthorize("@el.check('options:export')") + public void downloadLog(HttpServletResponse response, LogQueryCriteria criteria) throws IOException { + criteria.setLogType("INFO"); + criteria.setType(Arrays.asList(LogTypeEnum.SHOW_ADD_PARAMS.value(), LogTypeEnum.SHOW_PLAT_PARAMS.value(), LogTypeEnum.NO_PLAT_PARAMS.value())); + logService.download(logService.queryAll(criteria), response); + } + + @Log("导出登录日志数据") + @ApiOperation("导出登录日志数据") + @GetMapping(value = "/queryLogin/download") + @PreAuthorize("@el.check('login:export')") + public void downloadLogin(HttpServletResponse response, LogQueryCriteria criteria) throws IOException { + criteria.setLogType("INFO"); + criteria.setType(Arrays.asList(LogTypeEnum.SHOW_LOGIN_PARAMS.value())); + logService.download(logService.queryAll(criteria), response); + } + + @Log("导出错误数据") + @ApiOperation("导出错误数据") + @GetMapping(value = "/error/download") +// @PreAuthorize("@el.check()") + public void downloadErrorLog(HttpServletResponse response, LogQueryCriteria criteria) throws IOException { + criteria.setLogType("ERROR"); + logService.download(logService.queryAll(criteria), response); + } + + @GetMapping(value = "/queryLog") + @ApiOperation("日志查询") + @PreAuthorize("@el.check('options:list')") + public ResponseEntity queryLog(LogQueryCriteria criteria, Pageable pageable){ + criteria.setLogType("INFO"); + criteria.setType(Arrays.asList(LogTypeEnum.SHOW_ADD_PARAMS.value(), LogTypeEnum.SHOW_PLAT_PARAMS.value(), LogTypeEnum.NO_PLAT_PARAMS.value())); + return new ResponseEntity<>(logService.queryAll(criteria,pageable), HttpStatus.OK); + } + + @GetMapping(value = "/queryLogin") + @ApiOperation("日志查询") + @PreAuthorize("@el.check('login:list')") + public ResponseEntity queryLogin(LogQueryCriteria criteria, Pageable pageable){ + criteria.setLogType("INFO"); + criteria.setType(Arrays.asList(LogTypeEnum.SHOW_LOGIN_PARAMS.value())); + return new ResponseEntity<>(logService.queryAll(criteria,pageable), HttpStatus.OK); + } + + /** + * 根据id 修改前后日志变化详情 + * @param id + * @return + */ + @GetMapping(value = "/updateDetail/{id}") + @ApiOperation("日志查询") +// @PreAuthorize("@el.check()") + public Dto updateDetail(@PathVariable Long id){ + return Dto.returnResult(logService.queryUpdateDatail(id)); + } + + + + @GetMapping(value = "/user") + @ApiOperation("用户日志查询") + public ResponseEntity queryUserLog(LogQueryCriteria criteria, Pageable pageable){ + criteria.setLogType("INFO"); + criteria.setBlurry(SecurityUtils.getCurrentUsername()); + return new ResponseEntity<>(logService.queryAllByUser(criteria,pageable), HttpStatus.OK); + } + + @GetMapping(value = "/error") + @ApiOperation("错误日志查询") +// @PreAuthorize("@el.check()") + public ResponseEntity queryErrorLog(LogQueryCriteria criteria, Pageable pageable){ + criteria.setLogType("ERROR"); + return new ResponseEntity<>(logService.queryAll(criteria,pageable), HttpStatus.OK); + } + + @GetMapping(value = "/error/{id}") + @ApiOperation("日志异常详情查询") +// @PreAuthorize("@el.check()") + public ResponseEntity queryErrorLogs(@PathVariable Long id){ + return new ResponseEntity<>(logService.findByErrDetail(id), HttpStatus.OK); + } + @DeleteMapping(value = "/del/error") + @Log("删除所有ERROR日志") + @ApiOperation("删除所有ERROR日志") +// @PreAuthorize("@el.check()") + public ResponseEntity delAllErrorLog(){ + logService.delAllByError(); + return new ResponseEntity<>(HttpStatus.OK); + } + + @DeleteMapping(value = "/del/logInfo") + @Log("删除所有INFO操作日志") + @ApiOperation("删除所有INFO操作日志") + @PreAuthorize("@el.check('options:del')") + public ResponseEntity delAllLogInfo(){ + logService.deleteByLogTypeAndType("INFO", Arrays.asList(LogTypeEnum.SHOW_ADD_PARAMS.value(), LogTypeEnum.NO_PLAT_PARAMS.value(), LogTypeEnum.SHOW_PLAT_PARAMS.value())); + return new ResponseEntity<>(HttpStatus.OK); + } + + @DeleteMapping(value = "/del/loginInfo") + @Log("删除所有INFO登录日志") + @ApiOperation("删除所有INFO登录日志") + @PreAuthorize("@el.check('login:del')") + public ResponseEntity delAllLoginInfo(){ + logService.deleteByLogTypeAndType("INFO", Arrays.asList(LogTypeEnum.SHOW_LOGIN_PARAMS.value())); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/wjcy-logging/src/main/java/me/zhengjie/service/LogService.java b/wjcy-logging/src/main/java/me/zhengjie/service/LogService.java new file mode 100644 index 0000000..0dc6497 --- /dev/null +++ b/wjcy-logging/src/main/java/me/zhengjie/service/LogService.java @@ -0,0 +1,101 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.service; + +import me.zhengjie.domain.Log; +import me.zhengjie.service.dto.LogQueryCriteria; +import org.aspectj.lang.ProceedingJoinPoint; +import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Async; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; + +/** + * @author Zheng Jie + * @date 2018-11-24 + */ +public interface LogService { + + /** + * 分页查询 + * @param criteria 查询条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(LogQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部数据 + * @param criteria 查询条件 + * @return / + */ + List queryAll(LogQueryCriteria criteria); + + /** + * 查询修改数据详情 + * @param id 查询条件 + * @return / + */ + Object queryUpdateDatail(Long id); + + /** + * 查询用户日志 + * @param criteria 查询条件 + * @param pageable 分页参数 + * @return - + */ + Object queryAllByUser(LogQueryCriteria criteria, Pageable pageable); + + /** + * 保存日志数据 + * @param username 用户 + * @param browser 浏览器 + * @param ip 请求IP + * @param joinPoint / + * @param log 日志实体 + */ + @Async + void save(String username, String browser, String ip, ProceedingJoinPoint joinPoint, Log log, Object beforeJson); + + /** + * 查询异常详情 + * @param id 日志ID + * @return Object + */ + Object findByErrDetail(Long id); + + /** + * 导出日志 + * @param logs 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List logs, HttpServletResponse response) throws IOException; + + /** + * 删除所有错误日志 + */ + void delAllByError(); + + /** + * 删除所有INFO日志 + */ + void delAllByInfo(); + + void deleteByLogTypeAndType(String logType, List typeList); +} diff --git a/wjcy-logging/src/main/java/me/zhengjie/service/dto/LogErrorDTO.java b/wjcy-logging/src/main/java/me/zhengjie/service/dto/LogErrorDTO.java new file mode 100644 index 0000000..bc0d4ec --- /dev/null +++ b/wjcy-logging/src/main/java/me/zhengjie/service/dto/LogErrorDTO.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.service.dto; + +import lombok.Data; +import java.io.Serializable; +import java.sql.Timestamp; + +/** +* @author Zheng Jie +* @date 2019-5-22 +*/ +@Data +public class LogErrorDTO implements Serializable { + + private Long id; + + private String username; + + private String description; + + private String method; + + private String params; + + private String browser; + + private String requestIp; + + private String address; + + private Timestamp createTime; +} \ No newline at end of file diff --git a/wjcy-logging/src/main/java/me/zhengjie/service/dto/LogQueryCriteria.java b/wjcy-logging/src/main/java/me/zhengjie/service/dto/LogQueryCriteria.java new file mode 100644 index 0000000..dcc41f6 --- /dev/null +++ b/wjcy-logging/src/main/java/me/zhengjie/service/dto/LogQueryCriteria.java @@ -0,0 +1,42 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.service.dto; + +import lombok.Data; +import me.zhengjie.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** + * 日志查询类 + * @author Zheng Jie + * @date 2019-6-4 09:23:07 + */ +@Data +public class LogQueryCriteria { + + @Query(blurry = "username,description,address,requestIp,method,params") + private String blurry; + + @Query + private String logType; + + @Query(type = Query.Type.IN) + private List type; + + @Query(type = Query.Type.BETWEEN) + private List createTime; +} diff --git a/wjcy-logging/src/main/java/me/zhengjie/service/dto/LogSmallDTO.java b/wjcy-logging/src/main/java/me/zhengjie/service/dto/LogSmallDTO.java new file mode 100644 index 0000000..d074fd1 --- /dev/null +++ b/wjcy-logging/src/main/java/me/zhengjie/service/dto/LogSmallDTO.java @@ -0,0 +1,40 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.service.dto; + +import lombok.Data; +import java.io.Serializable; +import java.sql.Timestamp; + +/** + * @author Zheng Jie + * @date 2019-5-22 + */ +@Data +public class LogSmallDTO implements Serializable { + + private String description; + + private String requestIp; + + private Long time; + + private String address; + + private String browser; + + private Timestamp createTime; +} diff --git a/wjcy-logging/src/main/java/me/zhengjie/service/impl/LogServiceImpl.java b/wjcy-logging/src/main/java/me/zhengjie/service/impl/LogServiceImpl.java new file mode 100644 index 0000000..2b96dca --- /dev/null +++ b/wjcy-logging/src/main/java/me/zhengjie/service/impl/LogServiceImpl.java @@ -0,0 +1,232 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.service.impl; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import lombok.RequiredArgsConstructor; +import me.zhengjie.domain.Log; +import me.zhengjie.enums.LogTypeEnum; +import me.zhengjie.repository.LogRepository; +import me.zhengjie.service.LogService; +import me.zhengjie.service.dto.LogQueryCriteria; +import me.zhengjie.service.mapstruct.LogErrorMapper; +import me.zhengjie.service.mapstruct.LogSmallMapper; +import me.zhengjie.utils.*; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.*; + +/** + * @author Zheng Jie + * @date 2018-11-24 + */ +@Service +@RequiredArgsConstructor +public class LogServiceImpl implements LogService { + private static final Logger log = LoggerFactory.getLogger(LogServiceImpl.class); + private final LogRepository logRepository; + private final LogErrorMapper logErrorMapper; + private final LogSmallMapper logSmallMapper; + + + @Override + public Object queryAll(LogQueryCriteria criteria, Pageable pageable) { + Page page = logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)), pageable); + String status = "ERROR"; + if (status.equals(criteria.getLogType())) { + return PageUtil.toPage(page.map(logErrorMapper::toDto)); + } + return page; + } + + @Override + public List queryAll(LogQueryCriteria criteria) { + return logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb))); + } + + @Override + public Object queryUpdateDatail(Long id) { + Log log = logRepository.findById(id).orElseGet(Log::new); + ValidationUtil.isNull(log.getId(), "Log", "id", id); + String details = log.getPlatParams(); + return Dict.create().set("platParams", new String(ObjectUtil.isNotNull(details) ? details : "")); + } + + @Override + public Object queryAllByUser(LogQueryCriteria criteria, Pageable pageable) { + Page page = logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)), pageable); + return PageUtil.toPage(page.map(logSmallMapper::toDto)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void save(String username, String browser, String ip, ProceedingJoinPoint joinPoint, Log log, Object beforeJson) { + + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + me.zhengjie.annotation.Log aopLog = method.getAnnotation(me.zhengjie.annotation.Log.class); + + // 方法路径 + String methodName = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()"; + + //参数值 + List argValues = new ArrayList<>(Arrays.asList(joinPoint.getArgs())); + + // 修改前的数据整理,仅仅只存储变化的数据即可 + StringBuilder params = new StringBuilder("[ "); + JSONArray jsonArray = new JSONArray(); + boolean showBoolean = false; + if (ObjectUtil.isNotEmpty(beforeJson) && LogTypeEnum.SHOW_PLAT_PARAMS.value().equals(log.getType())) { + jsonArray.add(jsonUnion(argValues.get(0), beforeJson)); + } + + if (LogTypeEnum.SHOW_PLAT_PARAMS.value().equals(log.getType()) || LogTypeEnum.SHOW_ADD_PARAMS.value().equals(log.getType())) { + showBoolean = true; + } + + //参数名称 + for (Object argValue : argValues) { + if (ObjectUtil.isNotEmpty(argValue)) { + params.append(EmptyAttributeFiler.emptyAttributeFilerToString(argValue)).append(" "); + if (showBoolean) { + if (log.getTrueList()) { + jsonArray = new JSONArray(argValue); + } else { + JSONObject tempBefJsonObj = new JSONObject(argValue); + jsonArray.add(tempBefJsonObj); + } + } + } + } + + // 描述 + if (log != null && ObjectUtil.isEmpty(log.getDescription())) { + log.setDescription(aopLog.value()); + } + assert log != null; + log.setRequestIp(ip); + + String loginPath = "login"; + if (loginPath.equals(signature.getName())) { + try { + username = new JSONObject(argValues.get(0)).get("username").toString(); + } catch (Exception e) { + LogServiceImpl.log.error(e.getMessage(), e); + } + } + log.setAddress(StringUtils.getLocalCityInfo(log.getRequestIp())); + log.setMethod(methodName); + log.setUsername(username); + log.setParams(params.toString() + " ]"); + if (showBoolean) { + log.setPlatParams(jsonArray.toString()); + } + log.setBrowser(browser); + logRepository.save(log); + } + + /** + * 赋值资源 + * 根据source中的key除吊target中多余的数据。 + * 使target数据结构保持和source一致 + * @param source + * @param target + * @return + */ + public JSONObject jsonUnion(Object source, Object target) { + + JSONObject targetObj = new JSONObject(target); + JSONObject sourceObj = new JSONObject(source); + + + Map objMap = new LinkedHashMap<>(); + + if (ObjectUtil.isNotEmpty(sourceObj)) { + for (Map.Entry sourceEntry: sourceObj.entrySet()) { + String key = sourceEntry.getKey(); + Object value = sourceEntry.getValue(); + + // 判断是否存在key + if (targetObj.containsKey(key)) { + objMap.put(key, targetObj.get(key)); + } + } + } + + return new JSONObject(objMap); + } + + @Override + public Object findByErrDetail(Long id) { + Log log = logRepository.findById(id).orElseGet(Log::new); + ValidationUtil.isNull(log.getId(), "Log", "id", id); + String details = log.getExceptionDetail(); + return Dict.create().set("exception", new String(ObjectUtil.isNotNull(details) ? details : "")); + } + + @Override + public void download(List logs, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (Log log : logs) { + Map map = new LinkedHashMap<>(); + map.put("用户名", log.getUsername()); + map.put("IP", log.getRequestIp()); + map.put("IP来源", log.getAddress()); + map.put("描述", log.getDescription()); + map.put("浏览器", log.getBrowser()); + map.put("请求耗时/毫秒", log.getTime()); + map.put("异常详情", new String(ObjectUtil.isNotNull(log.getExceptionDetail()) ? log.getExceptionDetail() : "")); + map.put("创建日期", log.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delAllByError() { + logRepository.deleteByLogType("ERROR"); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delAllByInfo() { + logRepository.deleteByLogType("INFO"); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteByLogTypeAndType(String logType, List typeList) { + logRepository.deleteByLogTypeAndTypeContains(logType, typeList); + } +} diff --git a/wjcy-logging/src/main/java/me/zhengjie/service/mapstruct/LogErrorMapper.java b/wjcy-logging/src/main/java/me/zhengjie/service/mapstruct/LogErrorMapper.java new file mode 100644 index 0000000..3ae02c9 --- /dev/null +++ b/wjcy-logging/src/main/java/me/zhengjie/service/mapstruct/LogErrorMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.domain.Log; +import me.zhengjie.service.dto.LogErrorDTO; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** + * @author Zheng Jie + * @date 2019-5-22 + */ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface LogErrorMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/wjcy-logging/src/main/java/me/zhengjie/service/mapstruct/LogSmallMapper.java b/wjcy-logging/src/main/java/me/zhengjie/service/mapstruct/LogSmallMapper.java new file mode 100644 index 0000000..9f2972a --- /dev/null +++ b/wjcy-logging/src/main/java/me/zhengjie/service/mapstruct/LogSmallMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.domain.Log; +import me.zhengjie.service.dto.LogSmallDTO; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** + * @author Zheng Jie + * @date 2019-5-22 + */ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface LogSmallMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/wjcy-system/pom.xml b/wjcy-system/pom.xml new file mode 100644 index 0000000..0998697 --- /dev/null +++ b/wjcy-system/pom.xml @@ -0,0 +1,128 @@ + + + + wjcy + me.zhengjie + 1.0 + + 4.0.0 + jar + wjcy-system + 核心模块 + + + 0.11.1 + + 5.8.0 + + + + + + me.zhengjie + wjcy-generator + 1.0 + + + me.zhengjie + wjcy-common + + + + + + + me.zhengjie + wjcy-tools + 1.0 + + + + + org.springframework.boot + spring-boot-starter-websocket + + + + + io.jsonwebtoken + jjwt-api + ${jjwt.version} + + + io.jsonwebtoken + jjwt-impl + ${jjwt.version} + + + io.jsonwebtoken + jjwt-jackson + ${jjwt.version} + + + + + ch.ethz.ganymed + ganymed-ssh2 + build210 + + + com.jcraft + jsch + 0.1.55 + + + + + com.github.oshi + oshi-core + 5.7.1 + + + + + org.quartz-scheduler + quartz + + + + + org.apache.rocketmq + rocketmq-client + 4.4.0 + + + + + + + + src/main/resources + + **/*.* + + + **/*.db + + true + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + + diff --git a/wjcy-system/src/main/java/me/zhengjie/AppRun.java b/wjcy-system/src/main/java/me/zhengjie/AppRun.java new file mode 100644 index 0000000..ed24406 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/AppRun.java @@ -0,0 +1,70 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie; + +import io.swagger.annotations.Api; +import me.zhengjie.annotation.rest.AnonymousGetMapping; +import me.zhengjie.utils.SpringContextHolder; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.boot.web.servlet.server.ServletWebServerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.web.bind.annotation.RestController; + +/** + * 开启审计功能 -> @EnableJpaAuditing + * + * @author Zheng Jie + * @date 2018/11/15 9:20:19 + */ +@EnableAsync +@RestController +@Api(hidden = true) +@SpringBootApplication +@EnableTransactionManagement +@EnableJpaAuditing(auditorAwareRef = "auditorAware") +public class AppRun { + + public static void main(String[] args) { + SpringApplication.run(AppRun.class, args); + } + + @Bean + public SpringContextHolder springContextHolder() { + return new SpringContextHolder(); + } + + @Bean + public ServletWebServerFactory webServerFactory() { + TomcatServletWebServerFactory fa = new TomcatServletWebServerFactory(); + fa.addConnectorCustomizers(connector -> connector.setProperty("relaxedQueryChars", "[]{}")); + return fa; + } + + /** + * 访问首页提示 + * + * @return / + */ + @AnonymousGetMapping("/") + public String index() { + return "Backend service started successfully"; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/aspect/FormSubmissionAspect.java b/wjcy-system/src/main/java/me/zhengjie/aspect/FormSubmissionAspect.java new file mode 100644 index 0000000..e1cfec0 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/aspect/FormSubmissionAspect.java @@ -0,0 +1,93 @@ +package me.zhengjie.aspect; + +import cn.hutool.core.util.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.annotation.FormSubmission; +import me.zhengjie.dto.Dto; +import me.zhengjie.modules.security.config.bean.SecurityProperties; +import me.zhengjie.utils.RedisUtils; +import me.zhengjie.utils.RequestHolder; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import static me.zhengjie.config.constant.Constants.FORM_SUB_TOKEN; +import static me.zhengjie.error.ErrorCodeEnum.FORM_SUBMISSION_REPETITION_ERROR; + +/** + *

+ * 表单提交 切面 + *

+ * + * @author: rch + * @since: 2022-08-30 + */ +@Component +@Aspect +@Slf4j +public class FormSubmissionAspect { + @Resource + private RedisUtils redisUtils; + @Resource + private SecurityProperties securityProperties; + + /** + * 配置切入点 + */ + @Pointcut("@annotation(me.zhengjie.annotation.FormSubmission)") + public void formSubMissionAspectPointcut() { + } + + /** 配置环绕通知,formSubMissionAspectPointcut()上注册的切入点 */ + @Around("formSubMissionAspectPointcut()") + public Object formSubMissionAspectAround(ProceedingJoinPoint joinPoint) throws Throwable { + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method signatureMethod = signature.getMethod(); + FormSubmission formSubMission = signatureMethod.getAnnotation(FormSubmission.class); + HttpServletRequest request = RequestHolder.getHttpServletRequest(); + String uri = request.getRequestURI(); + String token = request.getHeader(securityProperties.getHeader()); +// Object[] args = joinPoint.getArgs(); // 参数值 + if (formSubMission.isOpen() && ObjectUtil.isNotEmpty(token)) { + +// String key = FORM_SUB_TOKEN + uri + args.toString(); + String key = FORM_SUB_TOKEN + uri; + Long count = redisUtils.incrAndExpire(key, formSubMission.second()); + /** 设置成功count=1 */ + if (count == null || count > 1) { + return Dto.getInstance(FORM_SUBMISSION_REPETITION_ERROR); + } + } + return joinPoint.proceed(); + } + + /** 配置异常通知 */ + @AfterThrowing(pointcut = "formSubMissionAspectPointcut()", throwing = "e") + public void formSubMissionAspectAfterThrowing(JoinPoint joinPoint, Exception e) { + HttpServletRequest request = RequestHolder.getHttpServletRequest(); + String uri = request.getRequestURI(); + // 接口请求的参数 + Object[] args = joinPoint.getArgs(); + // 记录报错信息 + log.error("表单重复提交验证报错,请求的接口地址:{},请求参数:{}",uri,args); + } + + + private Map transitionToMap(Object object) { + if (ObjectUtil.isNotNull(object) && object instanceof Map){ + return (Map) object; + } + return new HashMap(16); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/config/ConfigurerAdapter.java b/wjcy-system/src/main/java/me/zhengjie/config/ConfigurerAdapter.java new file mode 100644 index 0000000..e76512b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/config/ConfigurerAdapter.java @@ -0,0 +1,88 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.config; + +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.alibaba.fastjson.support.config.FastJsonConfig; +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +/** + * WebMvcConfigurer + * + * @author Zheng Jie + * @date 2018-11-30 + */ +@Configuration +@EnableWebMvc +public class ConfigurerAdapter implements WebMvcConfigurer { + + /** 文件配置 */ + private final FileProperties properties; + + public ConfigurerAdapter(FileProperties properties) { + this.properties = properties; + } + + @Bean + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + config.addAllowedOrigin("*"); + config.addAllowedHeader("*"); + config.addAllowedMethod("*"); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + FileProperties.ElPath path = properties.getPath(); + String avatarUtl = "file:" + path.getAvatar().replace("\\","/"); + String pathUtl = "file:" + path.getPath().replace("\\","/"); + registry.addResourceHandler("/avatar/**").addResourceLocations(avatarUtl).setCachePeriod(0); + registry.addResourceHandler("/file/**").addResourceLocations(pathUtl).setCachePeriod(0); + registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/").setCachePeriod(0); + } + + @Override + public void configureMessageConverters(List> converters) { + // 使用 fastjson 序列化,会导致 @JsonIgnore 失效,可以使用 @JSONField(serialize = false) 替换 + FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); + List supportMediaTypeList = new ArrayList<>(); + supportMediaTypeList.add(MediaType.APPLICATION_JSON_UTF8); + FastJsonConfig config = new FastJsonConfig(); + config.setDateFormat("yyyy-MM-dd HH:mm:ss"); + config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect); + converter.setFastJsonConfig(config); + converter.setSupportedMediaTypes(supportMediaTypeList); + converter.setDefaultCharset(StandardCharsets.UTF_8); + converters.add(converter); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/config/CorsConfig.java b/wjcy-system/src/main/java/me/zhengjie/config/CorsConfig.java new file mode 100644 index 0000000..3cd3209 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/config/CorsConfig.java @@ -0,0 +1,20 @@ +package me.zhengjie.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +/** + *

+ * 跨域配置 + *

+ * + * @Author xx + * @Date 2021/7/28 + **/ +@Configuration +public class CorsConfig implements WebMvcConfigurer { + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new CorsInterceptor()).addPathPatterns("/**"); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/config/GoogleAuthProperties.java b/wjcy-system/src/main/java/me/zhengjie/config/GoogleAuthProperties.java new file mode 100644 index 0000000..bd5fcd0 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/config/GoogleAuthProperties.java @@ -0,0 +1,58 @@ +package me.zhengjie.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +/** + * Google Auth Properties + * @author rch + * @date 2020-08-25 + */ +@Component +@Configuration +public class GoogleAuthProperties { + + public static int SECRET_SIZE; + + public static String SEED; + + public static String RANDOM_NUMBER_ALGORITHM; + + public static String REDIS_GOOGLE_AUTH_KEY; + + public static String QR_CREATE_PREFIX_URL; + + /** default 3 - max 17 (from google docs)最多可偏移的时间*/ + public static int WINDOW_SIZE; + + @Value("${auth.secret_size}") + public void setSecretSize(int secretSize) { + SECRET_SIZE = secretSize; + } + + @Value("${auth.seed}") + public void setSEED(String SEED) { + GoogleAuthProperties.SEED = SEED; + } + + @Value("${auth.random_number_algorithm}") + public void setRandomNumberAlgorithm(String randomNumberAlgorithm) { + RANDOM_NUMBER_ALGORITHM = randomNumberAlgorithm; + } + + @Value("${auth.window_size}") + public void setWindowSize(int window_size) { + GoogleAuthProperties.WINDOW_SIZE = window_size; + } + + @Value("${auth.redis_google_auth_key}") + public void setRedisGoogleAuthKey(String redisGoogleAuthKey) { + REDIS_GOOGLE_AUTH_KEY = redisGoogleAuthKey; + } + + @Value("${auth.qr_create_prefix_url}") + public void setQrCreatePrefixUrl(String qrCreatePrefixUrl) { + QR_CREATE_PREFIX_URL = qrCreatePrefixUrl; + } +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/config/WebSocketConfig.java b/wjcy-system/src/main/java/me/zhengjie/config/WebSocketConfig.java new file mode 100644 index 0000000..f55f5c6 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/config/WebSocketConfig.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; + +/** + * @author ZhangHouYing + * @date 2019-08-24 15:44 + */ +@Configuration +public class WebSocketConfig { + + @Bean + public ServerEndpointExporter serverEndpointExporter() { + return new ServerEndpointExporter(); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/config/thread/AsyncTaskExecutePool.java b/wjcy-system/src/main/java/me/zhengjie/config/thread/AsyncTaskExecutePool.java new file mode 100644 index 0000000..8df107e --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/config/thread/AsyncTaskExecutePool.java @@ -0,0 +1,69 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.config.thread; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * 异步任务线程池装配类 + * @author https://juejin.im/entry/5abb8f6951882555677e9da2 + * @date 2019年10月31日15:06:18 + */ +@Slf4j +@Configuration +public class AsyncTaskExecutePool implements AsyncConfigurer { + + /** 注入配置类 */ + private final AsyncTaskProperties config; + + public AsyncTaskExecutePool(AsyncTaskProperties config) { + this.config = config; + } + + @Override + public Executor getAsyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + //核心线程池大小 + executor.setCorePoolSize(config.getCorePoolSize()); + //最大线程数 + executor.setMaxPoolSize(config.getMaxPoolSize()); + //队列容量 + executor.setQueueCapacity(config.getQueueCapacity()); + //活跃时间 + executor.setKeepAliveSeconds(config.getKeepAliveSeconds()); + //线程名字前缀 + executor.setThreadNamePrefix("el-async-"); + // setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务 + // CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + executor.initialize(); + return executor; + } + + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return (throwable, method, objects) -> { + log.error("===="+throwable.getMessage()+"====", throwable); + log.error("exception method:"+method.getName()); + }; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/config/thread/AsyncTaskProperties.java b/wjcy-system/src/main/java/me/zhengjie/config/thread/AsyncTaskProperties.java new file mode 100644 index 0000000..21fdfd8 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/config/thread/AsyncTaskProperties.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.config.thread; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 线程池配置属性类 + * @author https://juejin.im/entry/5abb8f6951882555677e9da2 + * @date 2019年10月31日14:58:18 + */ +@Data +@Component +@ConfigurationProperties(prefix = "task.pool") +public class AsyncTaskProperties { + + private int corePoolSize; + + private int maxPoolSize; + + private int keepAliveSeconds; + + private int queueCapacity; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/config/thread/TheadFactoryName.java b/wjcy-system/src/main/java/me/zhengjie/config/thread/TheadFactoryName.java new file mode 100644 index 0000000..4cc8ae9 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/config/thread/TheadFactoryName.java @@ -0,0 +1,63 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.config.thread; + +import org.springframework.stereotype.Component; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 自定义线程名称 + * @author Zheng Jie + * @date 2019年10月31日17:49:55 + */ +@Component +public class TheadFactoryName implements ThreadFactory { + + private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1); + private final ThreadGroup group; + private final AtomicInteger threadNumber = new AtomicInteger(1); + private final String namePrefix; + + public TheadFactoryName() { + this("el-pool"); + } + + private TheadFactoryName(String name){ + SecurityManager s = System.getSecurityManager(); + group = (s != null) ? s.getThreadGroup() : + Thread.currentThread().getThreadGroup(); + //此时namePrefix就是 name + 第几个用这个工厂创建线程池的 + this.namePrefix = name + + POOL_NUMBER.getAndIncrement(); + } + + @Override + public Thread newThread(Runnable r) { + //此时线程的名字 就是 namePrefix + -thread- + 这个线程池中第几个执行的线程 + Thread t = new Thread(group, r, + namePrefix + "-thread-"+threadNumber.getAndIncrement(), + 0); + if (t.isDaemon()) { + t.setDaemon(false); + } + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + return t; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/config/thread/ThreadPoolExecutorUtil.java b/wjcy-system/src/main/java/me/zhengjie/config/thread/ThreadPoolExecutorUtil.java new file mode 100644 index 0000000..9a36abd --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/config/thread/ThreadPoolExecutorUtil.java @@ -0,0 +1,42 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.config.thread; + +import me.zhengjie.utils.SpringContextHolder; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * 用于获取自定义线程池 + * @author Zheng Jie + * @date 2019年10月31日18:16:47 + */ +public class ThreadPoolExecutorUtil { + + public static ThreadPoolExecutor getPoll(){ + AsyncTaskProperties properties = SpringContextHolder.getBean(AsyncTaskProperties.class); + return new ThreadPoolExecutor( + properties.getCorePoolSize(), + properties.getMaxPoolSize(), + properties.getKeepAliveSeconds(), + TimeUnit.SECONDS, + new ArrayBlockingQueue<>(properties.getQueueCapacity()), + new TheadFactoryName() + ); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/aspect/LogAspect.java b/wjcy-system/src/main/java/me/zhengjie/modules/aspect/LogAspect.java new file mode 100644 index 0000000..5618c65 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/aspect/LogAspect.java @@ -0,0 +1,154 @@ +package me.zhengjie.modules.aspect; + + +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.annotation.type.LogActionType; +import me.zhengjie.annotation.type.LogDaoType; +import me.zhengjie.annotation.type.LogGetIdType; +import me.zhengjie.config.BeanFactory; +import me.zhengjie.domain.Log; +import me.zhengjie.dto.Dto; +import me.zhengjie.enums.LogTypeEnum; +import me.zhengjie.service.LogService; +import me.zhengjie.utils.*; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * @author rch + * @date 2020-08-20 + */ +@Component +@Aspect +@Slf4j +public class LogAspect { + + private final LogService logService; + + ThreadLocal currentTime = new ThreadLocal<>(); + + public LogAspect(LogService logService) { + this.logService = logService; + } + + /** + * 配置切入点 + */ + @Pointcut("@annotation(me.zhengjie.annotation.Log)") + public void logPointcut() { + // 该方法无方法体,主要为了让同类中其他方法使用此切入点 + } + + /** + * 配置环绕通知,使用在方法logPointcut()上注册的切入点 + * + * @param joinPoint join point for advice + */ + @Around("logPointcut()") + public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { + Object result; + currentTime.set(System.currentTimeMillis()); + + // 判断是否是修改 如果是修改则获取修改前的信息 + // 如果是修改时间记录json数组,第一个为修改前的json 第二个为修改后的json数据 + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + me.zhengjie.annotation.Log aopLog = method.getAnnotation(me.zhengjie.annotation.Log.class); + //修改之前的数据 + JSONObject beforeJson = new JSONObject(); + Integer type = LogTypeEnum.NO_PLAT_PARAMS.value(); + if (LogActionType.UPDATE.equals(aopLog.type()) && ObjectUtil.isNotEmpty(aopLog.daoNames())) { + + //参数值 获取ID + JSONObject afterJson = JSONObject.parseObject(JSONObject.toJSONString(joinPoint.getArgs()[0])); + String[] daoNames = aopLog.daoNames(); + + // mybatis Plus Dao + if (LogDaoType.MyBATISPLUS.equals(aopLog.daoType())) { + type = LogTypeEnum.SHOW_PLAT_PARAMS.value(); + for (int i = 0; i < daoNames.length; i++) { + String daoName = daoNames[i]; + String idKey = aopLog.idTypes()[i].getValue(); + String valueKey = aopLog.valuesTypes()[i].getValue(); + Map queryMap = new HashMap<>(16); + queryMap.put(StringUtil.underscoreName(idKey), Long.valueOf(afterJson.getString(valueKey))); + Object beforeObj = BeanFactory.getBean(daoName, BaseMapper.class).selectByMap(queryMap).get(0); + cn.hutool.json.JSONObject tempBefJsonObj = new cn.hutool.json.JSONObject(beforeObj); + beforeJson.putAll(tempBefJsonObj); + } + } + // springBoot Data Jpa -因为springBoot Data JPa 该种类型 数据库结果映射对象不是json类型。暂定不支持先不修改不管 + if (LogDaoType.SPRINGDATAJPA.equals(aopLog.daoType())) { + // 逻辑大体同上 + } + } + + // 新增 + if (LogActionType.ADD.equals(aopLog.type())) { + type = LogTypeEnum.SHOW_ADD_PARAMS.value(); + } + + // 登录 + if (LogActionType.LOGIN.equals(aopLog.type())) { + type = LogTypeEnum.SHOW_LOGIN_PARAMS.value(); + } + + result = joinPoint.proceed(); + Log log = new Log("INFO", System.currentTimeMillis() - currentTime.get(), type); + log.setTrueList(aopLog.trueList()); + if (LogActionType.LOGIN.equals(aopLog.type())) { + // 记录失败原因 + if (ObjectUtil.isNotNull(result) && result instanceof Dto) { + log.setDescription(((Dto) result).getMessage()); + } + } + currentTime.remove(); + HttpServletRequest request = RequestHolder.getHttpServletRequest(); + logService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request), joinPoint, log, beforeJson); + return result; + } + + /** + * 配置异常通知 + * + * @param joinPoint join point for advice + * @param e exception + */ + @AfterThrowing(pointcut = "logPointcut()", throwing = "e") + public void logAfterThrowing(JoinPoint joinPoint, Throwable e) { + System.out.println("---------"); + System.out.println(e); + System.out.println(joinPoint); + long now = System.currentTimeMillis(); + long time = now - currentTime.get(); + Integer value = LogTypeEnum.NO_PLAT_PARAMS.value(); + Log log = new Log("ERROR", time, value); + currentTime.remove(); + log.setExceptionDetail(ThrowableUtil.getStackTrace(e)); + HttpServletRequest request = RequestHolder.getHttpServletRequest(); + logService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request), (ProceedingJoinPoint) joinPoint, log, null); + } + + public String getUsername() { + try { + return SecurityUtils.getCurrentUsername(); + } catch (Exception e) { + return ""; + } + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/capital/controller/FileUploadController.java b/wjcy-system/src/main/java/me/zhengjie/modules/capital/controller/FileUploadController.java new file mode 100644 index 0000000..5a197d6 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/capital/controller/FileUploadController.java @@ -0,0 +1,51 @@ +package me.zhengjie.modules.capital.controller; + +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.annotation.Log; +import me.zhengjie.config.SystemConfig; +import me.zhengjie.dto.Dto; +import me.zhengjie.service.FileUploadService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; + +/** + *

+ * 图片上传 + *

+ * + * @author: rch + * @since: 2022-06-22 + */ +@Slf4j +@RestController +public class FileUploadController { + + @Resource + private FileUploadService fileUploadService; + + /** + * 后台管理图片上传 + */ + @Log("图片上传") + @PostMapping("/api/file/uploadFile") + public Dto apiUpload(HttpServletResponse response, HttpServletRequest request) throws IOException { + List filePaths = fileUploadService.uploadify(request, response); + return Dto.returnResult(null).setData("list", filePaths); + } + + /** + * 获取图片域名 + */ + @Log("图片上传") + @GetMapping("/api/file/doMainName") + public Dto doMainName() throws IOException { + return Dto.returnResult(SystemConfig.FILE_VISIT_ADDR); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/capital/controller/GoogleAuthController.java b/wjcy-system/src/main/java/me/zhengjie/modules/capital/controller/GoogleAuthController.java new file mode 100644 index 0000000..963532a --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/capital/controller/GoogleAuthController.java @@ -0,0 +1,144 @@ +package me.zhengjie.modules.capital.controller; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.Log; +import me.zhengjie.annotation.type.LogActionType; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.CtSettingSite; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.modules.system.service.UserService; +import me.zhengjie.modules.system.service.dto.GoogleAuthQrBarCodeUrlDTO; +import me.zhengjie.modules.system.service.dto.UpdateGoogleAuthDTO; +import me.zhengjie.modules.utils.GoogleAuthenticatorUtil; +import me.zhengjie.service.SettingSiteService; +import me.zhengjie.service.vo.AdminGoogleAuthInfoVO; +import me.zhengjie.service.vo.GoogleAuthInfoVO; +import me.zhengjie.utils.SecurityUtils; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; + +/** + *

+ * Google Authenticator + *

+ * + * @author: rch + * @since: 2020-08-25 + */ +@Validated +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/googleAuth") +public class GoogleAuthController { + + @Resource + private SettingSiteService settingSiteService; + @Resource + private UserService userService; + + private final String GoogleValue = "ConinUnion"; + +// /** +// * 验证身份验证码是否正确 +// * @param googleAuthCodeDTO +// * @return +// */ +// @Log(value = "验证身份验证码是否正确") +// @PostMapping(value = "/authcode") +// public Dto authcode(@Valid @RequestBody GoogleAuthCodeDTO googleAuthCodeDTO) { +// if (!settingSiteService.getGooleAuthSwitch()) { +// return Dto.returnResult(null); +// } +// return Dto.returnResult(GoogleAuthenticatorUtil.authcode(googleAuthCodeDTO.getCodes(), googleAuthCodeDTO.getSavedSecret())); +// } +// +// /** +// * 获取密钥 +// * @param googleAuthGenSecretDTO +// * @return +// */ +// @Log(value = "获取密钥") +// @PostMapping(value = "/genSecret") +// public Dto genSecret(@Valid @RequestBody GoogleAuthGenSecretDTO googleAuthGenSecretDTO, HttpServletRequest request) { +// if (!settingSiteService.getGooleAuthSwitch() || ObjectUtil.isEmpty(userService.findByName(googleAuthGenSecretDTO.getUserName()))) { +// return Dto.returnResult(null); +// } +// // redis 一个用户对应 一次匹配配置的SEED 对应唯一秘钥 +// return Dto.returnResult(GoogleAuthenticatorUtil.genSecret(googleAuthGenSecretDTO.getUserName(), request.getRemoteHost())); +// } + + /** + * 获取二维码图片URL + * @param googleAuthQrBarCodeUrlDTO + * @return + */ + @Log(value = "获取二维码图片URL") + @PostMapping(value = "/getQRBarcodeURL") + public Dto getQRBarcodeURL(@Valid @RequestBody GoogleAuthQrBarCodeUrlDTO googleAuthQrBarCodeUrlDTO, HttpServletRequest request) { + if (ObjectUtil.isEmpty(userService.findByName(googleAuthQrBarCodeUrlDTO.getUserName()))) { + return Dto.returnResult(null); + } + // 没有秘钥会生成一个存储在 redis中 一个用户对应 一次匹配配置的SEED 对应唯一秘钥 + GoogleAuthInfoVO googleAuthInfoVO = new GoogleAuthInfoVO(); + String secretValue = GoogleAuthenticatorUtil.genSecret(googleAuthQrBarCodeUrlDTO.getUserName(), request.getRemoteHost()); + googleAuthInfoVO.setSecret(secretValue); + googleAuthInfoVO.setUserName(googleAuthQrBarCodeUrlDTO.getUserName()); + googleAuthInfoVO.setQrBarCodeUrl(GoogleAuthenticatorUtil.getQRBarcodeURL(googleAuthQrBarCodeUrlDTO.getUserName(), GoogleValue, secretValue)); + return Dto.returnResult(googleAuthInfoVO); + } + + /** + * 判断GoogleAuth 是否开启 + * @return + */ + @Log(value = "判断GoogleAuth 是否开启") + @PostMapping(value = "/getOpenUse") + public Dto getOpenUse(HttpServletRequest request) { + + // 获取admin 信息 + AdminGoogleAuthInfoVO adminGoogleAuthInfoVO = new AdminGoogleAuthInfoVO(); + UserDetails userDetails = SecurityUtils.getCurrentUser(); + if (ObjectUtil.isEmpty(userDetails) || ObjectUtil.isEmpty(userDetails.getUsername())) { + return Dto.getInstance(ErrorCodeEnum.BAD_CREDENTIALS); + } + + String secretValue = GoogleAuthenticatorUtil.genSecret(userDetails.getUsername(), request.getRemoteHost()); + adminGoogleAuthInfoVO.setSecret(secretValue); + adminGoogleAuthInfoVO.setUserName(userDetails.getUsername()); + adminGoogleAuthInfoVO.setQrBarCodeUrl(GoogleAuthenticatorUtil.getQRBarcodeURL(userDetails.getUsername(), GoogleValue, secretValue)); + adminGoogleAuthInfoVO.setGogoleAuthSwitch(settingSiteService.getGooleAuthSwitch()); + + return Dto.returnResult(adminGoogleAuthInfoVO); + } + + + @Log(value = "修改Google开关", type = LogActionType.UPDATE) + @PostMapping(value = "/updateOpenUse") + public Dto updateOpenUse(@Valid @RequestBody UpdateGoogleAuthDTO updateGoogleAuthDTO) { + + Integer value = updateGoogleAuthDTO.getIsOpen(); + CtSettingSite ctSettingSite = new CtSettingSite(); + ctSettingSite.setSettingValue(String.valueOf(value)); + + QueryWrapper ctSettingSiteQuery = new QueryWrapper(); + ctSettingSiteQuery.eq("setting_key", "googleAuth"); + + return Dto.returnResult(settingSiteService.update(ctSettingSite, ctSettingSiteQuery)); + } + + + @Log(value = "获取Google开关") + @GetMapping(value = "/getGoogleSwitch") + @AnonymousAccess + public Dto getGoogleSwitch() { + + return Dto.returnResult(settingSiteService.getGooleAuthSwitch()); + }} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/capital/controller/LoginIpController.java b/wjcy-system/src/main/java/me/zhengjie/modules/capital/controller/LoginIpController.java new file mode 100644 index 0000000..a50fe80 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/capital/controller/LoginIpController.java @@ -0,0 +1,68 @@ +package me.zhengjie.modules.capital.controller; + +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.Log; +import me.zhengjie.annotation.type.LogActionType; +import me.zhengjie.dto.Dto; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.modules.capital.dto.AddLoginIpDTO; +import me.zhengjie.modules.capital.dto.EditLoginIpDTO; +import me.zhengjie.modules.capital.dto.IdDTO; +import me.zhengjie.service.LoginIpService; +import me.zhengjie.utils.PageUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/* + * + * @Description ip限制 + * @Date 2022/3/21 + * @Author zeng + */ +@Validated +@RestController +@RequestMapping("/api/ip") +@RequiredArgsConstructor +public class LoginIpController { + + final LoginIpService loginIpService; + + @PostMapping("/list") + public Dto list(@RequestBody @Valid PageDTO pageDTO) { + PageUtils pageUtils = loginIpService.getList(pageDTO.getiPage()); + return Dto.returnResult(pageUtils); + } + + @Log(type = LogActionType.ADD,value = "添加ip限制") + @PostMapping("/add") + public Dto addIp(@RequestBody @Valid AddLoginIpDTO dto) { + if (!dto.pass()) { + return Dto.getInstance(ErrorCodeEnum.LOGIN_IP_FORMAT_ERROR); + } + return Dto.returnResult(loginIpService.addIp(dto.getLoginIp())); + } + + @Log(type = LogActionType.UPDATE,value = "修改ip限制") + @PostMapping("/edit") + public Dto editIp(@RequestBody @Valid EditLoginIpDTO dto){ + if (!dto.pass()) { + return Dto.getInstance(ErrorCodeEnum.LOGIN_IP_FORMAT_ERROR); + } + return Dto.returnResult(loginIpService.updateIp(dto.getLoginIp())); + } + + @PostMapping("/getById") + public Dto getIp(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(loginIpService.getById(idDTO.getId())); + } + + @Log(type = LogActionType.DELETE,value = "删除ip限制") + @PostMapping("/del") + public Dto delIp(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(loginIpService.deleteIp(idDTO.getId().intValue())); + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/capital/controller/SettingSiteController.java b/wjcy-system/src/main/java/me/zhengjie/modules/capital/controller/SettingSiteController.java new file mode 100644 index 0000000..65d4498 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/capital/controller/SettingSiteController.java @@ -0,0 +1,140 @@ +package me.zhengjie.modules.capital.controller; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.annotation.FormSubmission; +import me.zhengjie.annotation.Log; +import me.zhengjie.annotation.type.LogActionType; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.CtSettingSite; +import me.zhengjie.modules.capital.dto.SettingSiteDTO; +import me.zhengjie.service.SettingSiteService; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 全局配置 控制类 + * + * @author rch + * @date 2020-07-29 + */ +@Validated +@RestController +@RequiredArgsConstructor +@RequestMapping("api/settingSite") +@Slf4j +public class SettingSiteController { + + @Resource + private SettingSiteService settingSiteService; + + + /** + * 获取全局配置 + * + * @return + */ + @Log("获取全局配置") + @PostMapping("/list") + public Dto list() { + List ctSettingSiteList = settingSiteService.list(); + List list = new ArrayList(); + for (CtSettingSite settingSite : ctSettingSiteList) { + Map map = BeanUtil.beanToMap(settingSite); + map.put("settingValue", getSettingValue(settingSite)); + list.add(map); + } + return Dto.returnResult(list); + } + + /** + * 配置全局配置 + * + * @param settingsiteDtoList + * @return + */ + @Log(value = "配置全局配置", type = LogActionType.ADD, trueList = true) + @PostMapping(value = "/save") + @FormSubmission + public Dto save(@Valid @RequestBody List settingsiteDtoList) { + + List updateCtSettingSiteList = new ArrayList<>(); + for (SettingSiteDTO settingSiteDTO : settingsiteDtoList) { + CtSettingSite site = new CtSettingSite(); + BeanUtil.copyProperties(settingSiteDTO, site); + + // 个别设置 可以只修改部分的内容 + switch (settingSiteDTO.getSettingKey()) { + case "shareholderCurrencySettings": { + String value = settingSiteService.getValue("shareholderCurrencySettings"); + JSONObject oldValue = JSONUtil.parseObj(value); + JSONObject updateValue = JSONUtil.parseObj(settingSiteDTO.getSettingValue()); + oldValue.putAll(updateValue); + site.setSettingValue(oldValue.toString()); + } + } + + updateCtSettingSiteList.add(site); + } + if (ObjectUtil.isEmpty(updateCtSettingSiteList)) { + return Dto.returnErrorResult(" Empty List! "); + } + + // 执行批量更新操作 + return Dto.returnResult(settingSiteService.updateBatchById(updateCtSettingSiteList)); + } + + + private Object getSettingValue(CtSettingSite settingSite) { + Object settingValue = settingSite.getSettingValue(); + switch (settingSite.getSettingKey()) { + case "currencyTemplateSettings": { + JSONObject jsonObject = JSONUtil.parseObj(settingSite.getSettingValue()); + List list = new ArrayList(); + for (String key : jsonObject.keySet()) { + JSONObject value = jsonObject.get(key, JSONObject.class); + value.putOpt("currencyName", key); + list.add(value); + } + return list; + } + case "shareholderPoolPublicSettings": { + JSONObject jsonObject = JSONUtil.parseObj(settingSite.getSettingValue()); + return jsonObject; + } + case "shareholderCurrencySettings": { + JSONObject jsonObject = JSONUtil.parseObj(settingSite.getSettingValue()); + List list = new ArrayList(); + for (String key : jsonObject.keySet()) { + Map blockChain = MapUtil.of("passType", key); + JSONObject currencys = jsonObject.get(key, JSONObject.class); + List currencyList = new ArrayList(); + for (String k : currencys.keySet()) { + JSONObject currency = currencys.get(k, JSONObject.class); + currency.putOpt("currencyName", k); + currencyList.add(currency); + } + blockChain.put("currency", currencyList); + list.add(blockChain); + } + + return list; + } + } + return settingValue; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/AddLoginIpDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/AddLoginIpDTO.java new file mode 100644 index 0000000..632652f --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/AddLoginIpDTO.java @@ -0,0 +1,50 @@ +package me.zhengjie.modules.capital.dto; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; +import me.zhengjie.annotation.DateTime; +import me.zhengjie.entity.LoginIp; +import me.zhengjie.utils.LoginIpUtil; + +import javax.validation.constraints.NotBlank; + +/* + * + * @Description + * @Date 2022/3/21 + * @Author zeng + */ +@Data +public class AddLoginIpDTO { + + /** 开始IP */ + @NotBlank + private String ipStart; + /** 结束IP */ + private String ipEnd; + /** 备注 */ + private String remark; + /** 有效截至时间 */ + @DateTime + private String vaildTime; + + public boolean pass() { + if (!LoginIpUtil.isIP(ipStart)) { + return false; + } + if (ObjectUtil.isNotEmpty(ipEnd) && !LoginIpUtil.isIP(ipEnd)) { + return false; + } + return true; + } + + public LoginIp getLoginIp() { + LoginIp ip = new LoginIp(); + ip.setIpStart(ipStart); + ip.setIpEnd(ipEnd); + ip.setRemark(remark); + ip.setVaildTime(vaildTime); + return ip; + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/EditLoginIpDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/EditLoginIpDTO.java new file mode 100644 index 0000000..7a493dd --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/EditLoginIpDTO.java @@ -0,0 +1,26 @@ +package me.zhengjie.modules.capital.dto; + +import lombok.Data; +import me.zhengjie.entity.LoginIp; + +import javax.validation.constraints.NotNull; + +/* + * + * @Description + * @Date 2022/3/21 + * @Author zeng + */ +@Data +public class EditLoginIpDTO extends AddLoginIpDTO{ + + @NotNull + private Integer id; + + @Override + public LoginIp getLoginIp() { + LoginIp loginIp = super.getLoginIp(); + loginIp.setId(id); + return loginIp; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/IdDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/IdDTO.java new file mode 100644 index 0000000..aee0b34 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/IdDTO.java @@ -0,0 +1,17 @@ +package me.zhengjie.modules.capital.dto; + +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/* + * + * @Description IdDTO + * @Date 2021/11/30 + * @Author zeng + */ +@Data +public class IdDTO { + @NotNull + private Long id; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/RelSettingSiteDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/RelSettingSiteDTO.java new file mode 100644 index 0000000..108c95c --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/RelSettingSiteDTO.java @@ -0,0 +1,27 @@ +package me.zhengjie.modules.capital.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 全局配置(SettingSiteDTO)表实体类 + * + * @author rch + * @since 2020-07-29 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RelSettingSiteDTO { + + @NotNull(message = "id不能为空") + private Long id; + + @Valid + List settingSiteList; +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/SettingSiteDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/SettingSiteDTO.java new file mode 100644 index 0000000..8c9229c --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/capital/dto/SettingSiteDTO.java @@ -0,0 +1,33 @@ +package me.zhengjie.modules.capital.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 全局配置(SettingSiteDTO)表实体类 + * + * @author rch + * @since 2020-07-29 + */ +@Slf4j +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SettingSiteDTO { + + @NotNull(message = "id不能为空") + private Long id; + + /** 设置KEY */ + @NotBlank(message = "设置KEY") + private String settingKey; + + /** 设置value */ + @NotBlank + private String settingValue; +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtApplyController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtApplyController.java new file mode 100644 index 0000000..aced8ee --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtApplyController.java @@ -0,0 +1,187 @@ +package me.zhengjie.modules.group.controller.base; + + +import cn.hutool.core.bean.BeanUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import me.zhengjie.annotation.FormSubmission; +import me.zhengjie.annotation.Log; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.CtApply; +import me.zhengjie.enums.TaskInfoEnum; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.modules.group.dto.CtApplyAddDTO; +import me.zhengjie.modules.group.dto.CtApplyListDTO; +import me.zhengjie.modules.group.dto.CtApplyUpdateDTO; +import me.zhengjie.modules.group.dto.IdDTO; +import me.zhengjie.service.CtApplyService; +import me.zhengjie.service.vo.CtApplyListVO; +import me.zhengjie.utils.PageUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Author: zhw + * Data: 2022-07-23 + * Description 应用管理控制层——CtApply + */ +@Validated +@RequestMapping("/api/ctApply") +@RestController +@Api(tags = "业务:应用管理") +public class CtApplyController { + + @Resource + private CtApplyService ctApplyService; + + /** + * 分页查询 + */ + @ApiOperation("分页查询应用数据") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询应用数据") + @PostMapping("/list") + public Dto getApplyList(@Valid @RequestBody CtApplyListDTO dto){ + PageUtils pageUtils = ctApplyService.searchPageList(dto.getiPage(),dto.getWrapper()); + return Dto.returnResult(pageUtils); + } + + + /** + * 新增应用信息 + * @param dto + * @return Dto + */ + @ApiOperation("新增应用信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 4200, message = "应用ID存在重复!"), + @ApiResponse(code = 4201, message = "不存在对应方法名称!") + }) + @Log("新增应用信息") + @PostMapping("/add") + @FormSubmission + public Dto addCtApply(@Valid @RequestBody CtApplyAddDTO dto){ + + List applyList = ctApplyService.list(); + List applyIdList = applyList.stream().map(CtApply::getRobotUuid).collect(Collectors.toList()); + if(applyIdList.contains(dto.getRobotUuid())){ + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_REPEAT_ID); + } + + CtApply ctApply = new CtApply(); + BeanUtil.copyProperties(dto, ctApply); + //任务名首字母小写 + char[] taskNameChars = dto.getTaskName().toCharArray(); + taskNameChars[0] = Character.toLowerCase(taskNameChars[0]); + String taskName = new String(taskNameChars); + String methodName = TaskInfoEnum.getMethodNameByTaskName(taskName); + if(methodName == null || methodName.length() == 0){ + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_METHOD_NAME); + } + ctApply.setTaskName(taskName); + ctApply.setMethodName(methodName); + return Dto.returnResult(ctApplyService.save(ctApply)); + } + + /** + * 根据ID删除应用信息 + * @param idDTO + * @return Dto + */ + @ApiOperation("根据ID删除应用信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据ID删除应用信息") + @PostMapping("/delete") + public Dto delCtApplyById(@Valid @RequestBody IdDTO idDTO){ + return Dto.returnResult(ctApplyService.removeById(idDTO.getId())); + } + + /** + * 根据ID 修改应用信息 + * @param dto + * @return Dto + */ + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 4200, message = "应用ID存在重复!"), + @ApiResponse(code = 4201, message = "不存在对应方法名称!") + }) + @ApiOperation("修改应用信息") + @Log("根据ID修改应用信息") + @PostMapping("/edit") + @FormSubmission + public Dto editCtApplyById(@Valid @RequestBody CtApplyUpdateDTO dto){ + CtApply ctApplyIsExist = ctApplyService.getById(dto.getId()); + if(ctApplyIsExist == null){ + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_APPLY); + } + CtApply updateCtApply = new CtApply(); + BeanUtil.copyProperties(dto,updateCtApply); + //更新校验 + List applyList = ctApplyService.list(); + List applyIdList = applyList.stream().map(CtApply::getRobotUuid).collect(Collectors.toList()); + if(applyIdList.contains(dto.getRobotUuid()) && !dto.getRobotUuid().equals(ctApplyIsExist.getRobotUuid())){ + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_REPEAT_ID); + } + + //任务名首字母小写 + char[] taskNameChars = dto.getTaskName().toCharArray(); + taskNameChars[0] = Character.toLowerCase(taskNameChars[0]); + String taskName = new String(taskNameChars); + String methodName = TaskInfoEnum.getMethodNameByTaskName(taskName); + //判断是否存在对应方法名称 + if(methodName == null || methodName.length() == 0){ + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_METHOD_NAME); + } + updateCtApply.setTaskName(taskName); + updateCtApply.setMethodName(methodName); + return Dto.returnResult(ctApplyService.updateById(updateCtApply)); + } + + /** + * 根据ID 查询应用信息 + * @param idDTO + * @return Dto + */ + @ApiOperation("查询应用信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据ID查询应用信息") + @PostMapping("getById") + public Dto getById(@Valid @RequestBody IdDTO idDTO){ + return Dto.returnResult(ctApplyService.getById(idDTO.getId())); + } + + /** + * 获取所有应用信息 + * @return Dto + */ + @ApiOperation("查找所有应用名称") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("查找所有应用名称") + @GetMapping("getAll") + public Dto getAllApply(){ + return Dto.returnResult(ctApplyService.getAllApplyName()); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtBrowseController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtBrowseController.java new file mode 100644 index 0000000..f22c5bd --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtBrowseController.java @@ -0,0 +1,148 @@ +package me.zhengjie.modules.group.controller.base; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.FormSubmission; +import me.zhengjie.annotation.Log; +import me.zhengjie.annotation.type.LogActionType; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.CtBrowse; +import me.zhengjie.enums.ClickBrowseStatusEnum; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.modules.group.dto.CtBrowseAddDTO; +import me.zhengjie.modules.group.dto.CtBrowseListDTO; +import me.zhengjie.modules.group.dto.CtBrowseUpdateDTO; +import me.zhengjie.modules.group.dto.IdDTO; +import me.zhengjie.service.CtBrowseService; +import me.zhengjie.service.vo.CtBrowseDetailVO; +import me.zhengjie.service.vo.CtBrowseListVO; +import me.zhengjie.utils.PageUtils; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.validation.Valid; + + +/** + * + * @Description 浏览收藏 控制类 + * @Date 2022-11-04 + * @Author rch + */ +@Validated +@RequestMapping("/api/ctBrowse") +@RestController +@RequiredArgsConstructor +@Api(tags = "业务:收藏浏览管理") +public class CtBrowseController { + + @Resource + private CtBrowseService ctBrowseService; + + /** + * 分页查询浏览收藏信息 + */ + @ApiOperation("分页查询浏览收藏数据") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询浏览收藏信息") + @PostMapping("/list") + public Dto getBrowseList(@Valid @RequestBody CtBrowseListDTO dto) { + PageUtils pageUtilsResult = ctBrowseService.searchPageList(dto.getiPage(), dto.getWrapper()); + return Dto.returnResult(pageUtilsResult); + } + + /** + * 新增浏览收藏信息 + */ + @ApiOperation("新增浏览收藏") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "新增浏览收藏信息",type = LogActionType.ADD) + @PostMapping("/add") + @FormSubmission + public Dto addBrowse(@Valid @RequestBody CtBrowseAddDTO dto) { + + CtBrowse ctBrowse = new CtBrowse(); + BeanUtil.copyProperties(dto, ctBrowse); + return Dto.returnResult(ctBrowseService.save(ctBrowse)); + } + + /** + * 根据Id获取浏览收藏详情 + */ + @ApiOperation("根据Id获取浏览收藏详情") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + + @Log("根据Id获取浏览收藏详情") + @PostMapping("/getById") + public Dto getBrowseById(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(ctBrowseService.getBrowseDetailById(idDTO.getId())); + } + + + /** + * 根据id删除 + * @author: rch + */ + @ApiOperation("根据id删除") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3300, message = "浏览信息不存在!") + }) + @Log(value = "根据id删除信息",type = LogActionType.DELETE) + @PostMapping("/delete") + public Dto delete(@Valid @RequestBody IdDTO idDTO) { + + // 先查询 + CtBrowse ctBrowse = ctBrowseService.getById(idDTO.getId()); + if (ObjectUtil.isEmpty(ctBrowse) + || !ClickBrowseStatusEnum.TOBE_EXECUTION.eqValue(ctBrowse.getStatus())) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_BROWSE); + } + return Dto.returnResult(ctBrowseService.removeById(idDTO.getId())); + } + + /** + * 编辑浏览收藏信息 + */ + @ApiOperation("编辑浏览收藏信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3301, message = "浏览收藏信息不存在!") + }) + @Log(value = "编辑浏览收藏信息",type = LogActionType.UPDATE) + @PostMapping("/edit") + @FormSubmission + public Dto editBrowse(@Valid @RequestBody CtBrowseUpdateDTO dto) { + + // 根据id 判断是否存在 + CtBrowse ctBrowse = ctBrowseService.getById(dto.getId()); + if (ObjectUtil.isEmpty(ctBrowse)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_BROWSE); + } + + CtBrowse updateCtBrowse = new CtBrowse(); + BeanUtil.copyProperties(dto, updateCtBrowse); + + return Dto.returnResult(ctBrowseService.updateById(updateCtBrowse)); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtBuyerController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtBuyerController.java new file mode 100644 index 0000000..6ef64e9 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtBuyerController.java @@ -0,0 +1,391 @@ +package me.zhengjie.modules.group.controller.base; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.Snowflake; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import io.swagger.annotations.*; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.FormSubmission; +import me.zhengjie.annotation.Log; +import me.zhengjie.annotation.type.LogActionType; +import me.zhengjie.config.PropertiesConfig; +import me.zhengjie.config.SystemConfig; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.*; +import me.zhengjie.enums.BuyerStatusEnum; +import me.zhengjie.enums.PlatTypeEnum; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.modules.group.dto.CtBuyerAddDTO; +import me.zhengjie.modules.group.dto.CtBuyerListDTO; +import me.zhengjie.modules.group.dto.CtBuyerUpdateDTO; +import me.zhengjie.modules.group.dto.IdDTO; +import me.zhengjie.service.*; +import me.zhengjie.service.vo.CtBuyerDetailVO; +import me.zhengjie.service.vo.CtBuyerListVO; +import me.zhengjie.utils.PageUtils; +import me.zhengjie.utils.excel.ExcelUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + + +/** + * + * @Description 群控管理-买家 控制类 + * @Date 2022-06-22 + * @Author rch + */ +@Validated +@RequestMapping("/api/ctBuyer") +@RestController +@RequiredArgsConstructor +@Api(tags = "业务:买家管理") +public class CtBuyerController { + + @Resource + private CtBuyerService ctBuyerService; + @Resource + private CtOrderService ctOrderService; + @Resource + private CtCompanyService ctCompanyService; + @Resource + private CtVpnService ctVpnService; + @Resource + private CtCardService ctCardService; + @Resource + private PropertiesConfig propertiesConfig; + @Resource + private Snowflake snowflake; + + /** + * 分页查询买家信息 + */ + @ApiOperation("分页查询买家数据") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询买家信息") + @PostMapping("/list") + public Dto getBuyerList(@Valid @RequestBody CtBuyerListDTO dto) { + PageUtils pageUtilsResult = ctBuyerService.searchPageList(dto.getiPage(), dto.getWrapper()); + return Dto.returnResult(pageUtilsResult); + } + + /** + * 新增买家信息 + */ + @ApiOperation("新增买家信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3200, message = "平台信息不存在!") + }) + @Log(value = "新增买家信息", type = LogActionType.ADD) + @PostMapping("/add") + @FormSubmission + public Dto addBuyer(@Valid @RequestBody CtBuyerAddDTO dto) { + // 检验 + Dto returnDto = addCheck(dto); + if (ObjectUtil.isNotEmpty(returnDto)) { + return returnDto; + } + + CtBuyer ctBuyer = new CtBuyer(); + BeanUtil.copyProperties(dto, ctBuyer); + return Dto.returnResult(ctBuyerService.save(ctBuyer)); + } + + /** + * 根据id买家信息详情详情 + */ + @ApiOperation("根据id查询买家详情信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据id查询买家详情信息") + @PostMapping("/getById") + public Dto getBuyerById(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(ctBuyerService.getDetailById(idDTO.getId())); + } + + /** + * 编辑买家信息 + */ + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3000, message = "买家信息不存在!"), + @ApiResponse(code = 3200, message = "平台信息不存在!") + }) + @ApiOperation("编辑买家信息") + @Log(value = "编辑买家信息", type = LogActionType.UPDATE) + @PostMapping("/edit") + @FormSubmission + public Dto editBuyer(@Valid @RequestBody CtBuyerUpdateDTO dto) { + + // 根据id 判断是否存在 + CtBuyer ctBuyer = ctBuyerService.getById(dto.getId()); + if (ObjectUtil.isEmpty(ctBuyer)) { + Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_BUYER_USER); + } + + // 如果修改平台平台信息 以及修改 密码信息 需要判断是否有关联的订单信息 存在则不允许修改 + Dto returnDto = equalsUpdateBuyerInfo(dto, ctBuyer); + if (ObjectUtil.isNotEmpty(returnDto)) { + return returnDto; + } + CtBuyer updateCtBuyer = new CtBuyer(); + BeanUtil.copyProperties(dto, updateCtBuyer); + return Dto.returnResult(ctBuyerService.updateById(updateCtBuyer)); + } + + /** + * 根据id删除买家信息 + * + * @author: rch + */ + @ApiOperation("根据ID删除买家信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "根据id删除买家信息", type = LogActionType.DELETE) + @PostMapping("/delete") + public Dto delBuyer(@Valid @RequestBody IdDTO idDTO) { + +// QueryWrapper queryWrapper = new QueryWrapper<>(); +// queryWrapper.eq("buyer_id", idDTO); +// Integer count = ctOrderService.count(queryWrapper); +// if (ObjectUtil.isNotEmpty(count) && count > 0) { +// Dto.getInstance(ErrorCodeEnum.ERROR_NOT_DEL_EXIST_ORDER_BUYER_USER); +// } + + CtBuyer updateCtBuyer = new CtBuyer(); + updateCtBuyer.setId(idDTO.getId()); + updateCtBuyer.setStatus(BuyerStatusEnum.DEL.value()); + + return Dto.returnResult(ctBuyerService.updateById(updateCtBuyer)); + } + + /** + * 新增逻辑 检验 + * + * @param dto + * @return + */ + public Dto addCheck(CtBuyerAddDTO dto) { + // 检验公司是否存在 + if (!ObjectUtil.isNotEmpty(ctCompanyService.getById(dto.getCompanyId()))) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_COMPANY); + } + + // 检验平台是否正确 + String value = PlatTypeEnum.getDescByType(dto.getPlatformId()); + if (ObjectUtil.isEmpty(value)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_PLAT_USER); + } + +// // 判断token是否重复 +// QueryWrapper queryWrapper = new QueryWrapper<>(); +// queryWrapper.eq("pwd", dto.getPwd()); +// Integer count = ctBuyerService.count(queryWrapper); +// if (ObjectUtil.isNotEmpty(count) && count > 1) { +// return Dto.getInstance(ErrorCodeEnum.ERROR_EXIST_FIND_BUYER_USER); +// } + return null; + } + + /** + * 检验是否是允许修改 + * + * @param dto + * @param ctBuyer + * @return + */ + public Dto equalsUpdateBuyerInfo(CtBuyerUpdateDTO dto, CtBuyer ctBuyer) { + Boolean canUpdate = false; + if (ObjectUtil.isNotEmpty(dto.getPwd()) && !dto.getPwd().equals(ctBuyer.getPwd())) { + canUpdate = true; + } + if (ObjectUtil.isNotEmpty(dto.getPlatformId()) && !dto.getPlatformId().equals(ctBuyer.getPlatformId())) { + canUpdate = true; + } + if (ObjectUtil.isNotEmpty(dto.getPlatformId()) && !dto.getPlatformId().equals(ctBuyer.getPlatformId())) { + canUpdate = true; + } + + if (canUpdate) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("buyer_id", dto.getId()); + Integer count = ctOrderService.count(queryWrapper); + if (ObjectUtil.isNotEmpty(count) && count > 1) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_UPDATE_EXIST_ORDER_BUYER_USER); + } + } + + // 检验公司是否存在 + if (!ObjectUtil.isNotEmpty(ctCompanyService.getById(dto.getCompanyId()))) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_COMPANY); + } + +// // 判断token是否重复 +// QueryWrapper queryWrapper = new QueryWrapper<>(); +// queryWrapper.eq("pwd", dto.getPwd()); +// Integer count = ctBuyerService.count(queryWrapper); +// if (ObjectUtil.isNotEmpty(count) && count > 1) { +// return Dto.getInstance(ErrorCodeEnum.ERROR_EXIST_FIND_BUYER_USER); +// } + return null; + } + + /** + * 从Excel导入买家信息 + */ + @ApiOperation("从Excel导入买家信息") + @ApiImplicitParams({ + @ApiImplicitParam(value = "上传文件", name = "file", dataType = "__file", required = true) + }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "Excel买家信息", type = LogActionType.ADD) + @PostMapping("import") + public Dto importBuyer(@RequestPart("file") MultipartFile file, HttpServletResponse response) throws Exception { + List ctBuyerImportList = ExcelUtils.readMultipartFile(file, CtBuyerImport.class); + //当excel表导入为空 + if (ObjectUtil.isEmpty(ctBuyerImportList)) { + return Dto.returnResult(false); + } + + List allBuyerAccount = ctBuyerService.getAllAccount(); + List companyInfoList = new ArrayList<>(); + //根据excel表中公司名称导出表中存在公司信息,自动过滤不存在的 + List buyerCompanyNameList = ctBuyerImportList.stream().map(CtBuyerImport::getCompanyName).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList()); + if (ObjectUtil.isNotEmpty(buyerCompanyNameList)) { + companyInfoList = ctCompanyService.getByNmae(buyerCompanyNameList); + } + //获取VPN列表 + List vpnInfoList = new ArrayList<>(); + List buyerVpnIpList = ctBuyerImportList.stream().map(CtBuyerImport::getVpnIp).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());; + if (ObjectUtil.isNotEmpty(buyerVpnIpList)) { + vpnInfoList = ctVpnService.getVpnInfoByIp(buyerVpnIpList); + } + //获取信用卡列表 + List cardInfoList = new ArrayList<>(); + List buyerCardNubList = ctBuyerImportList.stream().map(CtBuyerImport::getCardNumber).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());; + if (ObjectUtil.isNotEmpty(buyerCardNubList)) { + cardInfoList = ctCardService.getCardInfoByNumber(buyerCardNubList); + } + + //批量新增的买家 + List addCtBuyerList = new ArrayList<>(); + //导出异常的买家信息 + List ctBuyerExportList = new ArrayList<>(); + + //循环判断异常 + for (CtBuyerImport ctBuyerImport : ctBuyerImportList) { + //定义一个异常买家实体 + CtBuyerExport ctBuyerExport = new CtBuyerExport(); + BeanUtil.copyProperties(ctBuyerImport, ctBuyerExport); + + StringBuffer errorStrBuf = new StringBuffer(); + //错误信息 + String rowTips = ctBuyerImport.getRowTips(); + if (ObjectUtil.isNotEmpty(rowTips)) { + errorStrBuf.append(rowTips); + errorStrBuf.append(";"); + } + + if (allBuyerAccount.contains(ctBuyerImport.getAccount())) { + errorStrBuf.append("已存在该账号对应的买家信息"); + errorStrBuf.append(";"); + } + //判断是否存在该公司 + if (ObjectUtil.isEmpty(companyInfoList) || companyInfoList.stream().filter(i -> i.getName().equals(ctBuyerExport.getCompanyName())).count() < 1) { + errorStrBuf.append("公司名称不存在!"); + errorStrBuf.append(";"); + } + if (ObjectUtil.isEmpty(vpnInfoList) || vpnInfoList.stream().filter(i -> i.getIpAddress().equals(ctBuyerExport.getVpnIp())).count() < 1) { + errorStrBuf.append("VpnIP信息不存在!"); + errorStrBuf.append(";"); + } + // 敦煌的不需要检验信用卡 + if (!"敦煌".equals(ctBuyerImport.getPlatformName())) { + if (ObjectUtil.isEmpty(cardInfoList) || cardInfoList.stream().filter(i -> i.getNumber().equals(ctBuyerExport.getCardNumber())).count() < 1) { + errorStrBuf.append("信用卡卡号信息不存在!"); + errorStrBuf.append(";"); + } + } + + // 平台 + Integer platId = PlatTypeEnum.getValueByDesc(ctBuyerImport.getPlatformName()); + if (ObjectUtil.isEmpty(platId)) { + errorStrBuf.append("平台信息不存在!"); + errorStrBuf.append(";"); + } + + if (ObjectUtil.isNotEmpty(errorStrBuf)) { + ctBuyerExport.setError(errorStrBuf.toString()); + ctBuyerExportList.add(ctBuyerExport); + } else { + CtBuyer ctBuyer = new CtBuyer(); + BeanUtil.copyProperties(ctBuyerImport, ctBuyer); + //平台ID + ctBuyer.setPlatformId(platId); + //公司ID + Optional ctCompanyInfo = companyInfoList.stream().filter(c -> c.getName().equals(ctBuyerImport.getCompanyName())).findFirst(); + ctBuyer.setCompanyId(ctCompanyInfo.get().getId()); + //VPNiD + Optional ctVpnInfo = vpnInfoList.stream().filter(c -> c.getIpAddress().equals(ctBuyerImport.getVpnIp())).findFirst(); + ctBuyer.setVpnId(ctVpnInfo.get().getId()); + //信用卡ID + Optional ctCardInfo = cardInfoList.stream().filter(c -> c.getNumber().equals(ctBuyerImport.getCardNumber())).findFirst(); + ctBuyer.setCardId(ctCardInfo.get().getId()); + addCtBuyerList.add(ctBuyer); + } + } + String returnDataStr = null; + String filePath = propertiesConfig.getUploadImgPath().get(PublicConstant.EXPORT_EXCEL_FILE_TYPE); + String fileName = "买家导入异常信息表-" + snowflake.nextIdStr(); + if (ObjectUtil.isNotEmpty(ctBuyerExportList)) { + ExcelUtils.exportFile(SystemConfig.IMG_PATH + filePath, fileName, ctBuyerExportList); + returnDataStr = SystemConfig.FILE_VISIT_ADDR + filePath + fileName + ".xlsx"; + // returnDataStr = "http://localhost:8008/file" + filePath + fileName + ".xlsx"; + } + + if (ObjectUtil.isNotEmpty(addCtBuyerList)) { + ctBuyerService.saveBatch(addCtBuyerList); + } + + return Dto.returnResult(ObjectUtil.isEmpty(returnDataStr) ? true : returnDataStr); + } + + /** + * ExcelVpn信息模板导出 + */ + @ApiOperation("买家信息Excel模版导出") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "买家信息Excel模版导出") + @GetMapping("/exportTemp") + @AnonymousAccess + public void exportBuyer(HttpServletResponse response) { + ExcelUtils.exportTemplate(response, "买家导入模板", CtBuyerExportTemple.class); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtCardController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtCardController.java new file mode 100644 index 0000000..e7d0888 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtCardController.java @@ -0,0 +1,307 @@ +package me.zhengjie.modules.group.controller.base; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.lang.Snowflake; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import io.swagger.annotations.*; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.FormSubmission; +import me.zhengjie.annotation.Log; +import me.zhengjie.annotation.type.LogActionType; +import me.zhengjie.config.PropertiesConfig; +import me.zhengjie.config.SystemConfig; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.CtCard; +import me.zhengjie.entity.CtCardExport; +import me.zhengjie.entity.CtCardExportTemple; +import me.zhengjie.entity.CtCardImport; +import me.zhengjie.enums.CardStatusEnum; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.modules.group.dto.CtCardAddDTO; +import me.zhengjie.modules.group.dto.CtCardListDTO; +import me.zhengjie.modules.group.dto.CtCardUpdateDTO; +import me.zhengjie.modules.group.dto.IdDTO; +import me.zhengjie.service.CtCardService; +import me.zhengjie.service.vo.CtCardDetailVO; +import me.zhengjie.service.vo.CtCardListVO; +import me.zhengjie.utils.PageUtils; +import me.zhengjie.utils.excel.ExcelUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + + +/** + * + * @Description 群控管理-信用卡 控制类 + * @Date 2022-06-22 + * @Author rch + */ +@Validated +@RequestMapping("/api/ctCard") +@RestController +@RequiredArgsConstructor +@Api(tags = "业务:信用卡管理") +public class CtCardController { + + @Resource + private CtCardService ctCardService; + @Resource + private PropertiesConfig propertiesConfig; + @Resource + private Snowflake snowflake; + + /** + * 分页查询信用卡信息 + */ + @ApiOperation("分页查询信用卡数据") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询信用卡信息") + @PostMapping("/list") + public Dto getCardList(@Valid @RequestBody CtCardListDTO dto) { + IPage page= ctCardService.page(dto.getiPage(), dto.getWrapper()); + List list = new ArrayList<>(); + for (CtCard record : page.getRecords()) { + CtCardListVO vo = new CtCardListVO(); + BeanUtil.copyProperties(record, vo); + list.add(vo); + } + + PageUtils pageUtils = new PageUtils(page.getTotal(),list); + return Dto.returnResult(pageUtils); + } + + /** + * 新增信用卡信息 + */ + @ApiOperation("新增信用卡") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "新增信用卡信息",type = LogActionType.ADD) + @PostMapping("/add") + @FormSubmission + public Dto addCard(@Valid @RequestBody CtCardAddDTO dto) { + + CtCard ctCard = new CtCard(); + BeanUtil.copyProperties(dto, ctCard); + return Dto.returnResult(ctCardService.save(ctCard)); + } + + /** + * 根据Id获取信用卡详情 + */ + @ApiOperation("根据Id获取信用卡详情") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据Id获取信用卡详情") + @PostMapping("/getById") + public Dto getCardById(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(ctCardService.getById(idDTO.getId())); + } + + + /** + * 根据id删除信用卡信息 + * @author: rch + */ + @ApiOperation("根据id删除信用卡信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3300, message = "信用卡信息不存在,或者已删除或异常!") + }) + @Log(value = "根据id删除信用卡信息",type = LogActionType.DELETE) + @PostMapping("/delete") + public Dto delCard(@Valid @RequestBody IdDTO idDTO) { + + // 先查询 + CtCard ctCard = ctCardService.getById(idDTO.getId()); + if (ObjectUtil.isEmpty(ctCard) || CardStatusEnum.DEL.eqValue(ctCard.getStatus())) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_CARD_INFO); + } + + CtCard updateCtCard = new CtCard(); + updateCtCard.setId(idDTO.getId()); + updateCtCard.setStatus(CardStatusEnum.DEL.value()); + + return Dto.returnResult(ctCardService.updateById(updateCtCard)); + } + + + /** + * 根据id修改信用卡状态异常 + * @author: rch + */ + @ApiOperation("根据id修改信用卡状态异常") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3300, message = "信用卡信息不存在,或者已删除或异常!") + }) + @Log(value = "根据id修改信用卡状态异常",type = LogActionType.UPDATE) + @PostMapping("/abMormal") + public Dto abMormal(@Valid @RequestBody IdDTO idDTO) { + + // 先查询 + CtCard ctCard = ctCardService.getById(idDTO.getId()); + if (ObjectUtil.isEmpty(ctCard) || CardStatusEnum.AB_NORMAL.eqValue(ctCard.getStatus())) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_CARD_INFO); + } + + CtCard updateCtCard = new CtCard(); + updateCtCard.setId(idDTO.getId()); + updateCtCard.setStatus(CardStatusEnum.AB_NORMAL.value()); + + return Dto.returnResult(ctCardService.updateById(updateCtCard)); + } + + + /** + * 编辑信用卡信息 + */ + @ApiOperation("编辑信用卡信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3301, message = "信用卡信息不存在!") + }) + @Log(value = "编辑信用卡信息",type = LogActionType.UPDATE) + @PostMapping("/edit") + @FormSubmission + public Dto editCard(@Valid @RequestBody CtCardUpdateDTO dto) { + + // 根据id 判断是否存在 + CtCard ctCard = ctCardService.getById(dto.getId()); + if (ObjectUtil.isEmpty(ctCard)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_CARD); + } + + CtCard updateCard = new CtCard(); + BeanUtil.copyProperties(dto, updateCard); + + return Dto.returnResult(ctCardService.updateById(updateCard)); + } + + /** + * Excel导入信用卡信息 + * @param file + * @param response + * @return + * @throws Exception + */ + @ApiOperation("Excel导入信用卡信息") + @ApiImplicitParams({ + @ApiImplicitParam(value = "上传文件", name = "file", dataType = "__file", required = true) + }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "Excel导入信用卡信息",type = LogActionType.ADD) + @PostMapping("/import") + public Dto importCard(@RequestPart("file")MultipartFile file, HttpServletResponse response) throws Exception { + + // TODO 对Excel 信息进行检测 如果不符合要求的 最终要导出错误Excel提示 + List ctCardImportList = ExcelUtils.readMultipartFile(file, CtCardImport.class); + if (ObjectUtil.isEmpty(ctCardImportList)) { + return Dto.returnResult(true); + } + + List addCtCardList = new ArrayList<>(); + List numberValueList = ctCardService.getNumberList(); + List ctCardExportList = new ArrayList<>(); + for (CtCardImport ctCardImport:ctCardImportList) { + CtCardExport ctCardExport = new CtCardExport(); + BeanUtil.copyProperties(ctCardImport, ctCardExport); + + StringBuffer errorStrBuf = new StringBuffer(); + String rowTips = ctCardImport.getRowTips(); + if (ObjectUtil.isNotEmpty(rowTips)) { + errorStrBuf.append(rowTips); + errorStrBuf.append(";"); + } + if (numberValueList.contains(ctCardImport.getNumber())) { + errorStrBuf.append("平台已经存在改卡号对应的信用卡信息!"); + errorStrBuf.append(";"); + } + // 判断日期格式是否正确 + String termOfValidity = ctCardImport.getTermOfValidity(); + String datePattern = "\\d{4}-\\d{1,2}-\\d{1,2}"; + if (!termOfValidity.matches(datePattern)) { + errorStrBuf.append("时间格式错误(yyyy-MM-dd)!"); + errorStrBuf.append(";"); + } + if (ObjectUtil.isNotEmpty(errorStrBuf)) { + ctCardExport.setError(errorStrBuf.toString()); + ctCardExportList.add(ctCardExport); + } else { + CtCard ctCard = new CtCard(); + BeanUtils.copyProperties(ctCardImport, ctCard); + addCtCardList.add(ctCard); + } + } + + String returnDataStr = null; + String filePath = propertiesConfig.getUploadImgPath().get(PublicConstant.EXPORT_EXCEL_FILE_TYPE); + String fileName = "信用卡导入异常信息表-" + snowflake.nextIdStr(); + if (ObjectUtil.isNotEmpty(ctCardExportList)) { + ExcelUtils.exportFile(SystemConfig.IMG_PATH + filePath, fileName, ctCardExportList); + returnDataStr = SystemConfig.FILE_VISIT_ADDR + filePath + fileName + ".xlsx"; +// returnDataStr = "http://localhost:8008/file" + filePath + fileName + ".xlsx"; + } + + if (ObjectUtil.isNotEmpty(addCtCardList)) { + ctCardService.saveBatch(addCtCardList); + } + + return Dto.returnResult(returnDataStr); + +// // 剔除已经有的了 +// List numberList = ctCardList.stream().map(CtCard::getNumber).collect(Collectors.toList()); +// if (ObjectUtil.isEmpty(numberValueList)) { +// return Dto.returnResult(true); +// } +// List finalNumberList = (List) CollectionUtils.subtract(numberList, numberValueList); +// if (ObjectUtil.isEmpty(finalNumberList)) { +// return Dto.returnResult(true); +// } +// ctCardList = ctCardList.stream().filter(c-> finalNumberList.contains(c.getNumber())).collect(Collectors.toList()); + + } + + + /** + * Excel信用卡信息模版导出 + * @param response + */ + @ApiOperation("Excel信用卡信息模版导出") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "Excel信用卡信息模版导出") + @GetMapping("/exportTemp") + @AnonymousAccess + public void importCard(HttpServletResponse response) { + ExcelUtils.exportTemplate(response, "信用卡模版", CtCardExportTemple.class); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtClickFarmingController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtClickFarmingController.java new file mode 100644 index 0000000..3e481cc --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtClickFarmingController.java @@ -0,0 +1,301 @@ +package me.zhengjie.modules.group.controller.base; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.Snowflake; +import cn.hutool.core.util.ObjectUtil; +import io.swagger.annotations.*; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.FormSubmission; +import me.zhengjie.annotation.Log; +import me.zhengjie.annotation.type.LogActionType; +import me.zhengjie.config.PropertiesConfig; +import me.zhengjie.config.SystemConfig; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.*; +import me.zhengjie.enums.ClickFarmingStatusEnum; +import me.zhengjie.enums.ParamsTypeEnum; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.modules.group.dto.CtClickFarmingAddDTO; +import me.zhengjie.modules.group.dto.CtClickFarmingDTO; +import me.zhengjie.modules.group.dto.CtClickFarmingEditDTO; +import me.zhengjie.modules.group.dto.IdDTO; +import me.zhengjie.service.CtBuyerService; +import me.zhengjie.service.CtClickFarmingService; +import me.zhengjie.service.vo.CtClickFarmEditDetailVO; +import me.zhengjie.service.vo.CtClickFarmingDetailVO; +import me.zhengjie.service.vo.CtClickFarmingVO; +import me.zhengjie.utils.PageUtils; +import me.zhengjie.utils.excel.ExcelUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +/** + * + * @Description 群控管理-刷单信息 控制类 + * @Date 2022-06-22 + * @Author rch + */ +@Validated +@RequestMapping("/api/clickFarming") +@RestController +@RequiredArgsConstructor +@Api(tags = "业务:刷单信息管理") +public class CtClickFarmingController { + + @Resource + private CtClickFarmingService ctClickFarmingService; + @Resource + private PropertiesConfig propertiesConfig; + @Resource + private CtBuyerService ctBuyerService; + @Resource + private Snowflake snowflake; + + /** + * 分页查询刷单信息 + */ + @ApiOperation("分页查询刷单数据") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询刷单信息") + @PostMapping("/list") + public Dto getClickFarmingList(@Valid @RequestBody CtClickFarmingDTO dto) { + PageUtils pageUtilsResult = ctClickFarmingService.searchPageList(dto.getiPage(), dto.getWrapper()); + return Dto.returnResult(pageUtilsResult); + } + + /** + * 新增刷单信息 + */ + @ApiOperation("新增刷单信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "新增刷单信息",type = LogActionType.ADD) + @PostMapping("/add") + @FormSubmission + public Dto addClickFarming(@Valid @RequestBody CtClickFarmingAddDTO dto) { + + CtClickFarming ctClickFarming = new CtClickFarming(); + BeanUtil.copyProperties(dto, ctClickFarming); + return Dto.returnResult(ctClickFarmingService.save(ctClickFarming)); + } + + /** + * 根据id获取刷单信息 + */ + @ApiOperation("根据id获取刷单信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据id获取刷单信息") + @PostMapping("/getById") + public Dto getById(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(ctClickFarmingService.getDetailById(idDTO.getId())); + } + + /** + * 根据id获取修改回显信息 + */ + @ApiOperation("根据id获取修改回显信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据id获取修改回显信息") + @PostMapping("/getEditDetailById") + public Dto getEditDetailById(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(ctClickFarmingService.getEditDetailById(idDTO.getId())); + } + + /** + * 根据id删除刷单信息 + * @author: rch + */ + @ApiOperation("根据id删除刷单信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3300, message = "信用卡信息不存在,或者已删除或异常!"), + @ApiResponse(code = 3901, message = "只有待执行的刷单信息才允许删除!") + }) + @Log(value = "根据id删除刷单信息",type = LogActionType.DELETE) + @PostMapping("/delete") + public Dto delClickFarming(@Valid @RequestBody IdDTO idDTO) { + + // 先查询 + CtClickFarming ctClickFarming = ctClickFarmingService.getById(idDTO.getId()); + if (ObjectUtil.isEmpty(ctClickFarming)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_CARD_INFO); + } + + if (!ClickFarmingStatusEnum.TOBE_EXECUTION.eqValue(ctClickFarming.getStatus())) { + return Dto.getInstance(ErrorCodeEnum.ERROR_DEL_CLICKFARMING_INFO); + } + + return Dto.returnResult(ctClickFarmingService.removeById(idDTO.getId())); + } + + /** + * 编辑刷单信息 + */ + @ApiOperation("编辑刷单信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3900, message ="刷单信息不存在!") + }) + @Log(value = "编辑刷单信息",type = LogActionType.UPDATE) + @PostMapping("/edit") + @FormSubmission + public Dto editClickFarming(@Valid @RequestBody CtClickFarmingEditDTO dto) { + // 判断状态 只有待执行状态太允许修改 + CtClickFarming ctClickFarming = ctClickFarmingService.getByIdLock(dto.getId()); + if (ObjectUtil.isEmpty(ctClickFarming)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_CLICKFARMING_INFO); + } + + CtClickFarming updateCtClickFarming = new CtClickFarming(); + BeanUtil.copyProperties(dto, updateCtClickFarming); + + return Dto.returnResult(ctClickFarmingService.updateById(updateCtClickFarming)); + } + + /** + * + * @param file + * @param response + * @return + * @throws Exception + */ + @ApiOperation("Excel刷单信息导入") + @ApiImplicitParams({ + @ApiImplicitParam(value = "上传文件", name = "file", dataType = "__file", required = true) + }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "Excel刷单信息导入",type = LogActionType.ADD) + @PostMapping("/import") + public Dto importClickFarming(@RequestPart("file")MultipartFile file, HttpServletResponse response) throws Exception { + + // TODO 对Excel 信息进行检测 如果不符合要求的 最终要导出错误Excel提示 + List ctClickFarmingImportList = ExcelUtils.readMultipartFile(file, CtClickFarmingImport.class); + if (ObjectUtil.isEmpty(ctClickFarmingImportList)) { + return Dto.returnResult(true); + } + + List addCtClickFarmingList = new ArrayList<>(); + List ctClickFarmingExportList = new ArrayList<>(); + + // 买家id + List buyerAccountList = ctClickFarmingImportList.stream().map(c->c.getAccount()).collect(Collectors.toList()); + Map buyerMap = ctBuyerService.getBuyerList(buyerAccountList); + + for (CtClickFarmingImport ctClickFarmingImport:ctClickFarmingImportList) { + CtClickFarmingExport ctClickFarmingExport = new CtClickFarmingExport(); + BeanUtil.copyProperties(ctClickFarmingImport, ctClickFarmingExport); + + StringBuffer errorStrBuf = new StringBuffer(); + String rowTips = ctClickFarmingImport.getRowTips(); + if (ObjectUtil.isNotEmpty(rowTips)) { + errorStrBuf.append(rowTips); + errorStrBuf.append(";"); + } + + if (ObjectUtil.isEmpty(ctClickFarmingImport.getSpecification())) { + errorStrBuf.append("规格-必填!"); + errorStrBuf.append(";"); + } + if (ObjectUtil.isEmpty(ctClickFarmingImport.getColor())) { + errorStrBuf.append("颜色-必填!"); + errorStrBuf.append(";"); + } + if (ObjectUtil.isEmpty(ctClickFarmingImport.getExchange())) { + errorStrBuf.append("优惠劵-必填!"); + errorStrBuf.append(";"); + } + + // 判断类型 + if (ParamsTypeEnum.KEY_WORD.eqValue(ctClickFarmingImport.getParamsType())) { + if (ObjectUtil.isEmpty(ctClickFarmingImport.getKeyWord())) { + errorStrBuf.append("关键词-必填!"); + errorStrBuf.append(";"); + } + if (ObjectUtil.isEmpty(ctClickFarmingImport.getTitle())) { + errorStrBuf.append("标题-必填!"); + errorStrBuf.append(";"); + } + if (ObjectUtil.isEmpty(ctClickFarmingImport.getItem())) { + errorStrBuf.append("item-必填!"); + errorStrBuf.append(";"); + } + } else { + if (ObjectUtil.isEmpty(ctClickFarmingImport.getLink())) { + errorStrBuf.append("链接-必填!"); + errorStrBuf.append(";"); + } + } + + if (ObjectUtil.isEmpty(buyerMap) || !buyerMap.containsKey(ctClickFarmingImport.getAccount())) { + errorStrBuf.append("买家信息不存在!"); + errorStrBuf.append(";"); + } else { + Long buyerId = buyerMap.entrySet().stream().collect(Collectors.toMap(entity -> entity.getKey(), entity -> entity.getValue())).get(ctClickFarmingImport.getAccount()).getId(); + ctClickFarmingImport.setBuyerId(buyerId); + } + if (ObjectUtil.isNotEmpty(errorStrBuf)) { + ctClickFarmingExport.setError(errorStrBuf.toString()); + ctClickFarmingExportList.add(ctClickFarmingExport); + } else { + CtClickFarming ctClickFarming = new CtClickFarming(); + BeanUtils.copyProperties(ctClickFarmingImport, ctClickFarming); + addCtClickFarmingList.add(ctClickFarming); + } + } + + String returnDataStr = null; + String filePath = propertiesConfig.getUploadImgPath().get(PublicConstant.EXPORT_EXCEL_FILE_TYPE); + String fileName = "刷单信息导入异常信息表-" + snowflake.nextIdStr(); + if (ObjectUtil.isNotEmpty(ctClickFarmingExportList)) { + ExcelUtils.exportFile(SystemConfig.IMG_PATH + filePath, fileName, ctClickFarmingExportList); + returnDataStr = SystemConfig.FILE_VISIT_ADDR + filePath + fileName + ".xlsx"; +// returnDataStr = "http://localhost:8008/file" + filePath + fileName + ".xlsx"; + } + + if (ObjectUtil.isNotEmpty(addCtClickFarmingList)) { + ctClickFarmingService.saveBatch(addCtClickFarmingList); + } + + return Dto.returnResult(returnDataStr); + } + + @ApiOperation("Excel刷单信息模版导出") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "Excel刷单信息模版导出") + @GetMapping("/exportTemp") + @AnonymousAccess + public void importClickFarming(HttpServletResponse response) { + ExcelUtils.exportTemplate(response, "刷单信息模版", CtClickFarmingExportTemp.class); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtClickOrderController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtClickOrderController.java new file mode 100644 index 0000000..fadc5d1 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtClickOrderController.java @@ -0,0 +1,330 @@ +package me.zhengjie.modules.group.controller.base; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.Snowflake; +import cn.hutool.core.util.ObjectUtil; +import io.swagger.annotations.*; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.Log; +import me.zhengjie.annotation.rest.AnonymousPostMapping; +import me.zhengjie.annotation.type.LogActionType; +import me.zhengjie.config.PropertiesConfig; +import me.zhengjie.config.SystemConfig; +import me.zhengjie.constant.Constants; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.*; +import me.zhengjie.enums.ClickFarmingStatusEnum; +import me.zhengjie.enums.OrderTypeEnum; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.modules.group.dto.*; +import me.zhengjie.service.CtClickFarmingService; +import me.zhengjie.service.CtClickOrderService; +import me.zhengjie.service.CtCompanyService; +import me.zhengjie.service.vo.CtClickOrderDetailVO; +import me.zhengjie.service.vo.CtClickOrderListVO; +import me.zhengjie.utils.PageUtils; +import me.zhengjie.utils.excel.ExcelUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + + +/** + * + * @Description 群控管理-刷单信息订单 控制类 + * @Date 2022-06-22 + * @Author rch + */ +@Validated +@RequestMapping("/api/clickOrder") +@RestController +@RequiredArgsConstructor +@Api(tags = "业务:刷单订单管理") +public class CtClickOrderController { + + @Resource + private CtClickOrderService ctClickOrderService; + @Resource + private CtCompanyService ctCompanyService; + @Resource + private PropertiesConfig propertiesConfig; + @Resource + private CtClickFarmingService ctClickFarmingService; + @Resource + private Snowflake snowflake; + + /** + * 分页查询刷单订单信息 + */ + @ApiOperation("分页查询刷单订单信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询刷单订单信息") + @PostMapping("/list") + @AnonymousAccess + public Dto getClickOrderList(@Valid @RequestBody CtClickOrderListDTO dto) { + PageUtils pageUtilsResult = ctClickOrderService.searchPageList(dto.getiPage(), dto.getWrapper()); + return Dto.returnResult(pageUtilsResult); + } + + /** + * 开放刷单订单接口给到ERP + * @param dto + * @return + */ + @ApiOperation("开放刷单订单接口") + @ApiImplicitParam(value = "鉴权token", name = "erpToken", paramType = "header", dataType = "String", required = true) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 4101, message = "鉴权信息不能为空!"), + @ApiResponse(code = 4102, message = "鉴权信息错误,请检查后重试!") + }) + @Log(value = "开放刷单订单接口") + @AnonymousPostMapping(value = "/searchClickOrder") + public Dto searchClickOrder(@Valid @RequestBody SearchOrderListDTO dto, HttpServletRequest request) { + + // 1.权限检验 + String erpToken = request.getHeader("erpToken"); + if (ObjectUtil.isEmpty(erpToken)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_NULL_ERP_AUTH_TOKEN); + } + + if (!Constants.ERP_AUTH_TOKEN.equals(erpToken)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_ERP_AUTH_TOKEN); + } + + // 2.根据请求条件查询记录并返回 + PageUtils pageUtilsResult = ctClickOrderService.searchPageList(dto.getiPage(), dto.getWrapper()); + return Dto.returnResult(pageUtilsResult); + } + + /** + * 根据id刷单信息详情详情 + */ + @ApiOperation("根据id刷单信息详情详情") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据id刷单信息详情详情") + @PostMapping("/getById") + public Dto getCardById(@Valid @RequestBody IdDTO idDTO) { + // 获取 + CtClickOrderDetailVO ctClickOrderDetailVO = ctClickOrderService.getClickOrderDetailById(idDTO.getId()); +// if (ObjectUtil.isNotEmpty(ctClickOrderDetailVO.getPaths())) { +// List pathStrList = new ArrayList<>(); +// List pathList = Arrays.asList(ctClickOrderDetailVO.getPaths().split(",")); +// for (String path:pathList) { +//// path = "http://localhost:8008/file" + path; +// path = SystemConfig.FILE_VISIT_ADDR + path; +// pathStrList.add(path); +// } +// ctClickOrderDetailVO.setPaths(pathStrList.stream().collect(Collectors.joining(","))); +// } + return Dto.returnResult(ctClickOrderDetailVO); + } + + + /** + * 新增订单评论信息 + */ + @ApiOperation("新增订单评论信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "新增订单评论信息") + @PostMapping("/add") + public Dto add(@Valid @RequestBody CtClickOrderAddDto ctClickOrderAddDto) { + + // 保证仅仅 下单成功并且支付失败状态才允许执行 + + CtClickOrder addCtClickOrder = new CtClickOrder(); + addCtClickOrder.setType(OrderTypeEnum.IMPORT.value()); + BeanUtil.copyProperties(ctClickOrderAddDto, addCtClickOrder); + return Dto.returnResult(ctClickOrderService.save(addCtClickOrder)); + } + + /** + * 刷单订单导入 + */ + @ApiOperation("Excel刷单订单导入") + @ApiImplicitParams({ + @ApiImplicitParam(value = "上传文件", name = "file", dataType = "__file", required = true) + }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "Excel刷单订单导入",type = LogActionType.ADD) + @PostMapping("import") + public Dto importOrder(@RequestPart("file") MultipartFile file, HttpServletResponse response)throws Exception{ + + //TODO 对Excel 信息进行检测 如果不符合要求的 最终要导出错误Excel提示 + List ctClickOrderImportList = ExcelUtils.readMultipartFile(file, CtClickOrderImport.class); + if(ObjectUtil.isEmpty(ctClickOrderImportList)){ + return Dto.returnResult(true); + } + + List addCtClickOrderList = new ArrayList<>(); + // 订单id 唯一 + List importOrderIdList = ctClickOrderImportList.stream().map(c->c.getOrderId()).collect(Collectors.toList()); + importOrderIdList = ctClickOrderService.getOrderId(importOrderIdList); + // 判断公司信息是否存在 + List companyNameList = ctClickOrderImportList.stream().map(c->c.getCompanyName()).collect(Collectors.toList()); + Map companyNameMap = ctCompanyService.getNameList(companyNameList); + + List ctClickOrderExportList = new ArrayList<>(); + for(CtClickOrderImport ctClickOrderImport : ctClickOrderImportList) { + CtClickOrderExport ctClickOrderExport = new CtClickOrderExport(); + BeanUtil.copyProperties(ctClickOrderImport, ctClickOrderExport); + + StringBuffer errorStrBuf = new StringBuffer(); + String rowTips = ctClickOrderImport.getRowTips(); + if (ObjectUtil.isNotEmpty((rowTips))) { + errorStrBuf.append(rowTips); + errorStrBuf.append(";"); + } + + String resultStr = checkImportInfo(importOrderIdList, companyNameMap, ctClickOrderImport); + if (ObjectUtil.isNotEmpty(resultStr)) { + errorStrBuf.append(resultStr); + errorStrBuf.append(";"); + } + + Long companyNameId = companyNameMap.entrySet().stream().collect(Collectors.toMap(entity -> entity.getValue(), entity -> entity.getKey())).get(ctClickOrderImport.getCompanyName()); + ctClickOrderImport.setCompanyId(companyNameId); + if (ObjectUtil.isNotEmpty(errorStrBuf)) { + ctClickOrderExport.setError(errorStrBuf.toString()); + ctClickOrderExportList.add(ctClickOrderExport); + } else { + CtClickOrder ctClickOrder = new CtClickOrder(); + BeanUtil.copyProperties(ctClickOrderImport, ctClickOrder); + ctClickOrder.setType(OrderTypeEnum.IMPORT.value()); + addCtClickOrderList.add(ctClickOrder); + } + } + + String returnDataStr = null; + String filePath = propertiesConfig.getUploadImgPath().get(PublicConstant.EXPORT_EXCEL_FILE_TYPE); + String fileName = "刷单订单导入异常信息表-" + snowflake.nextIdStr(); + if(ObjectUtil.isNotEmpty(ctClickOrderExportList)){ + ExcelUtils.exportFile(SystemConfig.IMG_PATH + filePath, fileName, ctClickOrderExportList); + returnDataStr = SystemConfig.FILE_VISIT_ADDR + filePath + fileName + ".xlsx"; + // returnDataStr = "http://localhost:8008/file" + filePath + fileName + ".xlsx"; + } + + if(ObjectUtil.isNotEmpty(addCtClickOrderList)){ + ctClickOrderService.saveBatch(addCtClickOrderList); + } + + return Dto.returnResult(returnDataStr); + } + + + + /** + * Excel订单模版导出 + */ + @ApiOperation("Excel订单模版导出") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "Excel订单模版导出") + @GetMapping("/exportTemp") + @AnonymousAccess + public void exportVpn(HttpServletResponse response) { + ExcelUtils.exportTemplate(response, "订单导入模板", CtClickOrderExportTemple.class, true); + } + + /** + * 补录订单信息 + * 仅仅 下单成功并且支付失败状态才允许执行此接口 + */ + @ApiOperation("补录订单信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3900, message = "刷单信息不存在!"), + @ApiResponse(code = 3903, message = "仅支付成功失败状态才允许补录!") + }) + @Log(value = "补录订单信息") + @PostMapping("/supplement") + public Dto supplementOrder(@Valid @RequestBody CtClickOrderSupplementDto ctClickOrderSupplementDto) { + + // 保证仅仅 下单成功并且支付失败状态才允许执行 + Long clickFarmingId = ctClickOrderSupplementDto.getClickFarmingId(); + CtClickFarming ctClickFarming = ctClickFarmingService.getById(clickFarmingId); + if (ObjectUtil.isEmpty(ctClickFarming)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_CLICKFARMING_INFO); + } + if (!ClickFarmingStatusEnum.PAY_OK_ERROR.value().equals(ctClickFarming.getStatus())) { + return Dto.getInstance(ErrorCodeEnum.ERROR_CLICKFARMING_NOT_SUPPLEMENT); + } + + CtClickOrder ctClickOrder = new CtClickOrder(); + BeanUtil.copyProperties(ctClickOrderSupplementDto, ctClickOrder); + // 补录订单信息 + return Dto.returnResult(ctClickOrderService.supplement(clickFarmingId, ctClickOrder)); + } + + + /** + * 新增评论信息 + */ + @ApiOperation("新增评论信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 4100, message = "订单信息不存在") + }) + @Log(value = "新增评论信息") + @PostMapping("/comment") + public Dto comment(@Valid @RequestBody CtClickOrderCommentDto ctClickOrderCommentDto) { + + // 保证仅仅 下单成功并且支付失败状态才允许执行 + CtClickOrder ctClickOrder = ctClickOrderService.getById(ctClickOrderCommentDto.getId()); + if (ObjectUtil.isEmpty(ctClickOrder)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_CLICK_ORDER_INFO); + } + + CtClickOrder updateCtClickOrder = new CtClickOrder(); + BeanUtil.copyProperties(ctClickOrderCommentDto, updateCtClickOrder); + return Dto.returnResult(ctClickOrderService.updateById(updateCtClickOrder)); + } + + /** + * 导入数据内容检验 + * @param importOrderIdList + * @param companyNameMap + * @param ctClickOrderImport + * @return + */ + public String checkImportInfo(List importOrderIdList, Map companyNameMap, CtClickOrderImport ctClickOrderImport) { + if (ObjectUtil.isNotEmpty(companyNameMap)) { + if (!companyNameMap.containsValue(ctClickOrderImport.getCompanyName())) { + return "对应名称的公司不存在!"; + } + } else if(ObjectUtil.isNotEmpty(ctClickOrderImport)) { + if (importOrderIdList.contains(ctClickOrderImport.getOrderId())) { + return "该笔订单已存在!"; + } + } + return null; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtCompanyController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtCompanyController.java new file mode 100644 index 0000000..88fa0fb --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtCompanyController.java @@ -0,0 +1,187 @@ +package me.zhengjie.modules.group.controller.base; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import me.zhengjie.annotation.FormSubmission; +import me.zhengjie.annotation.Log; +import me.zhengjie.annotation.type.LogActionType; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.CtBuyer; +import me.zhengjie.entity.CtCompany; +import me.zhengjie.entity.CtOrder; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.modules.group.dto.CtCompanyAddDTO; +import me.zhengjie.modules.group.dto.CtCompanyListDTO; +import me.zhengjie.modules.group.dto.CtCompanyUpdateDTO; +import me.zhengjie.modules.group.dto.IdDTO; +import me.zhengjie.service.CtCompanyService; +import me.zhengjie.service.CtOrderService; +import me.zhengjie.service.vo.CtCompanyInfoVO; +import me.zhengjie.service.vo.CtCompanyVO; +import me.zhengjie.utils.PageUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + + +/** + * + * @Description 群控管理-公司 控制类 + * @Date 2022-06-23 + * @Author rch + */ +@Validated +@RequestMapping("/api/ctCompany") +@RestController +@Api(tags = "业务:公司信息管理") +public class CtCompanyController { + + @Resource + private CtCompanyService ctCompanyService; + @Resource + private CtOrderService ctOrderService; + + /** + * 分页查询公司信息 + */ + @ApiOperation("分页查询公司信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询公司信息") + @PostMapping("/list") + public Dto getCompanyList(@Valid @RequestBody CtCompanyListDTO dto) { + IPage page = ctCompanyService.page(dto.getiPage(), dto.getWrapper()); + List list = new ArrayList<>(); + for (CtCompany record : page.getRecords()) { + CtCompanyVO ctCompanyVO = new CtCompanyVO(); + BeanUtil.copyProperties(record, ctCompanyVO); + list.add(ctCompanyVO); + } + PageUtils pageUtils = new PageUtils(page.getTotal(),list); + return Dto.returnResult(pageUtils); + } + + /** + * 新增公司信息 + */ + @ApiOperation("新增公司信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "新增公司信息",type = LogActionType.ADD) + @PostMapping("/add") + @FormSubmission + public Dto addCompany(@Valid @RequestBody CtCompanyAddDTO dto) { + CtCompany ctCompany = new CtCompany(); + BeanUtil.copyProperties(dto, ctCompany); + + // TODO 商户码(公司调用api公司唯一标识) -按照一定规则生成 + ctCompany.setNumber("666666"); + // TODO 商户token(公司调用api公司token身份标识)-按照一定规则生成 + ctCompany.setToken("7777777"); + return Dto.returnResult(ctCompanyService.save(ctCompany)); + } + + /** + * 根据id公司信息详情 + */ + @ApiOperation("根据id公司信息详情") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据id公司信息详情详情") + @PostMapping("/getById") + public Dto getCompanyById(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(ctCompanyService.getById(idDTO.getId())); + } + + /** + * 编辑公司信息 + */ + @ApiOperation("编辑公司信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3300, message = "公司信息不存在!") + }) + @Log(value = "编辑公司信息",type = LogActionType.UPDATE) + @PostMapping("/edit") + @FormSubmission + public Dto editCompany(@Valid @RequestBody CtCompanyUpdateDTO dto) { + + // TODO 检验平台ID和平台名称是否一致 + + // 根据id 判断是否存在 + CtCompany ctCompany = ctCompanyService.getById(dto.getId()); + if (ObjectUtil.isEmpty(ctCompany)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_COMPANY); + } + + CtCompany updateCtCompany = new CtCompany(); + BeanUtil.copyProperties(dto, updateCtCompany); + return Dto.returnResult(ctCompanyService.updateById(updateCtCompany)); + } + + /** + * 根据id删除公司信息 + * @author: rch + */ + @ApiOperation("根据id删除公司信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3201, message = "该公司下存在订单信息,不允许删除!") + }) + @Log(value = "根据id删除公司信息",type = LogActionType.DELETE) + @PostMapping("/delete") + public Dto delCompany(@Valid @RequestBody IdDTO idDTO) { + // 判断公司下存在订单信息则不允许删除 + QueryWrapper ctOrderQueryWrapper = new QueryWrapper<>(); + ctOrderQueryWrapper.eq("company_id", idDTO.getId()); + Integer count = ctOrderService.count(ctOrderQueryWrapper); + if (ObjectUtil.isNotEmpty(count) && count > 0) { + return Dto.getInstance(ErrorCodeEnum.ERROR_EXITS_CT_ORDER_INFO); + } + + return Dto.returnResult(ctCompanyService.removeById(idDTO.getId())); + } + + /** + * 获取所有公司信息 (公司id 公司名称) + * 为新增 公司提供公司所属公司服务 + * @return + */ + @ApiOperation("获取所有公司信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "获取所有公司信息") + @GetMapping("/getAll") + public Dto allCompany() { + List ctCompanyList = ctCompanyService.list(); + List ctCompanyInfoVOList = new ArrayList<>(); + if (ObjectUtil.isNotEmpty(ctCompanyList)) { + for (CtCompany ctCompany:ctCompanyList) { + CtCompanyInfoVO ctCompanyInfoVO = new CtCompanyInfoVO(); + BeanUtil.copyProperties(ctCompany, ctCompanyInfoVO); + ctCompanyInfoVOList.add(ctCompanyInfoVO); + } + } + return Dto.returnResult(ctCompanyInfoVOList); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtDhPayController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtDhPayController.java new file mode 100644 index 0000000..1fbf0b9 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtDhPayController.java @@ -0,0 +1,300 @@ +package me.zhengjie.modules.group.controller.base; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.Snowflake; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.qiniu.util.Json; +import io.swagger.annotations.*; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.FormSubmission; +import me.zhengjie.annotation.Log; +import me.zhengjie.annotation.type.LogActionType; +import me.zhengjie.config.PropertiesConfig; +import me.zhengjie.config.SystemConfig; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.CtDhPay; +import me.zhengjie.entity.CtDhPayExport; +import me.zhengjie.entity.CtDhPayExportTemple; +import me.zhengjie.entity.CtDhPayImport; +import me.zhengjie.enums.DhPayStatusEnum; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.modules.group.dto.CtDhPayAddDTO; +import me.zhengjie.modules.group.dto.CtDhPayListDTO; +import me.zhengjie.modules.group.dto.IdDTO; +import me.zhengjie.service.CtDhPayService; +import me.zhengjie.service.vo.CtDhPayDetailVO; +import me.zhengjie.service.vo.CtDhPayListVO; +import me.zhengjie.utils.PageUtils; +import me.zhengjie.utils.excel.ExcelUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + + +/** + * @Description 群控管理-敦煌支付 控制类 + * @Date 2022-06-22 + * @Author rch + */ +@Validated +@RequestMapping("/api/dhPay") +@RestController +@RequiredArgsConstructor +@Api(tags = "业务:敦煌支付管理") +public class CtDhPayController { + + @Resource + private PropertiesConfig propertiesConfig; + @Resource + private Snowflake snowflake; + @Resource + private CtDhPayService ctDhPayService; + + /** + * 分页查询敦煌支付信息 + */ + @ApiOperation("分页查询敦煌支付信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询敦煌支付信息") + @PostMapping("/list") + @AnonymousAccess + public Dto getDhPayList(@Valid @RequestBody CtDhPayListDTO dto) { + PageUtils pageUtilsResult = ctDhPayService.searchPageList(dto.getiPage(), dto.getWrapper()); + return Dto.returnResult(pageUtilsResult); + } + + /** + * 新增敦煌支付信息 + */ + @ApiOperation("新增敦煌支付信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "新增敦煌支付信息", type = LogActionType.ADD) + @PostMapping("/add") + @AnonymousAccess + @FormSubmission + public Dto addDhPay(@Valid @RequestBody CtDhPayAddDTO dto) { + List ctCardList = new ArrayList<>(); + List errCtDhPay = new ArrayList<>(); + String orderIdListStr = dto.getOrderId(); + String[] orderIdList = orderIdListStr.split(","); + List allCtDhPay = ctDhPayService.list(); + for (String orderId : orderIdList) { + CtDhPay ctDhPay = new CtDhPay(); + ctDhPay.setBuyerName(dto.getBuyerName()); + ctDhPay.setOrderId(orderId); + + // TODO 剔除已经存在的 同导入逻辑的检验 + List anyMatchList = allCtDhPay.stream().filter(d -> d.getBuyerName().equals(ctDhPay.getBuyerName()) && d.getOrderId().equals(ctDhPay.getOrderId())).collect(Collectors.toList()); + if (ObjectUtil.isNotEmpty(anyMatchList)) { + errCtDhPay.add(ctDhPay); + } else { + ctCardList.add(ctDhPay); + } + } + if (ObjectUtil.isNotEmpty(errCtDhPay)) { + StringBuffer errStrBuffer = new StringBuffer(); + errStrBuffer.append("该买家对应的订单编号"); + for (int i = 0; i < errCtDhPay.size(); i++) { + CtDhPay errPay = errCtDhPay.get(i); + if (i != 0) { + errStrBuffer.append("、"); + } + errStrBuffer.append(errPay.getOrderId()); + } + errStrBuffer.append("存在重复信息,新增失败"); + if (ObjectUtil.isNotEmpty(ctCardList)) { + ctDhPayService.saveBatch(ctCardList); + } + return Dto.returnErrorResult(errStrBuffer.toString()); + } else { + if (ObjectUtil.isNotEmpty(ctCardList)) { + return Dto.returnResult(ctDhPayService.saveBatch(ctCardList)); + } + } + return Dto.returnResult(true); + } + + /** + * 根据id敦煌支付信息 + */ + @ApiOperation("根据id敦煌支付信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据id敦煌支付信息") + @PostMapping("/getById") + @AnonymousAccess + public Dto getDhPayById(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(ctDhPayService.getById(idDTO.getId())); + } + + + /** + * 根据id删除敦煌支付信息 + * + * @author: rch + */ + @ApiOperation("根据id删除敦煌支付信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3800, message = "敦煌支付信息不存在,或已删除!") + }) + @Log(value = "根据id删除敦煌支付信息", type = LogActionType.DELETE) + @PostMapping("/delete") + @AnonymousAccess + public Dto delDhPay(@Valid @RequestBody IdDTO idDTO) { + + // 先查询 + CtDhPay ctDhPay = ctDhPayService.getById(idDTO.getId()); + if (ObjectUtil.isEmpty(ctDhPay) || DhPayStatusEnum.DEL.eqValue(ctDhPay.getStatus())) { + return Dto.getInstance(ErrorCodeEnum.ERROR_DH_PAY_NOT_FIND_OR_SUCCESS); + } + + CtDhPay updateCtDhPay = new CtDhPay(); + updateCtDhPay.setId(idDTO.getId()); + updateCtDhPay.setStatus(DhPayStatusEnum.DEL.value()); + + return Dto.returnResult(ctDhPayService.updateById(updateCtDhPay)); + } + + + /** + * Excel敦煌支付信息导入 + * @param file + * @param response + * @return + * @throws Exception + */ + @ApiOperation("Excel敦煌支付信息导入") + @ApiImplicitParams({ + @ApiImplicitParam(value = "上传文件", name = "file", dataType = "__file", required = true) + }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "Excel敦煌支付信息导入", type = LogActionType.ADD) + @PostMapping("/import") + public Dto importCard(@RequestPart("file") MultipartFile file, HttpServletResponse response) throws Exception { + + // TODO 对Excel 信息进行检测 如果不符合要求的 最终要导出错误Excel提示 + List ctDhPayImportList = ExcelUtils.readMultipartFile(file, CtDhPayImport.class); + if (ObjectUtil.isEmpty(ctDhPayImportList)) { + return Dto.returnResult(true); + } + + List addCtDhPayList = new ArrayList<>(); + List errCtDhPayList = new ArrayList<>(); + List ctDhPayExportList = new ArrayList<>(); + + List buyerNameList = ctDhPayImportList.stream().map(CtDhPayImport::getBuyerName).collect(Collectors.toList()); + List orderIdList = ctDhPayImportList.stream().map(CtDhPayImport::getOrderId).collect(Collectors.toList()); + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in("buyer_name", buyerNameList); + queryWrapper.or(); + queryWrapper.in("order_id", orderIdList); + List queryCtDhPay = ctDhPayService.list(queryWrapper); + + for (CtDhPayImport ctDhPayImport : ctDhPayImportList) { + CtDhPayExport ctDhPayExport = new CtDhPayExport(); + BeanUtil.copyProperties(ctDhPayImport, ctDhPayExport); + StringBuffer errorStrBuf = new StringBuffer(); + String rowTips = ctDhPayImport.getRowTips(); + if (ObjectUtil.isNotEmpty(rowTips)) { + errorStrBuf.append(rowTips); + errorStrBuf.append(";"); + } + //判断订单号是否按照规格输入 + String regex = "^[0-9]+(,[0-9]+)*$"; + if (!Pattern.matches(regex, ctDhPayImport.getOrderId())) { + errorStrBuf.append("订单编号格式输入错误,请重新输入"); + } else { + String[] orderIdArr = ctDhPayImport.getOrderId().split(","); + for (String orderId : orderIdArr) { + CtDhPay ctDhPay = new CtDhPay(); + ctDhPay.setBuyerName(ctDhPayImport.getBuyerName()); + ctDhPay.setOrderId(orderId); + + List anyMatchList = queryCtDhPay.stream().filter(d -> d.getBuyerName().equals(ctDhPay.getBuyerName()) && d.getOrderId().equals(ctDhPay.getOrderId())).collect(Collectors.toList()); + if (ObjectUtil.isNotEmpty(anyMatchList)) { + errCtDhPayList.add(ctDhPay); + } else { + addCtDhPayList.add(ctDhPay); + } + } + if (ObjectUtil.isNotEmpty(errCtDhPayList)) { + errorStrBuf.append("该买家对应的订单编号"); + for (int i = 0; i < errCtDhPayList.size(); i++) { + CtDhPay errPay = errCtDhPayList.get(i); + if (i != 0) { + errorStrBuf.append("、"); + } + errorStrBuf.append(errPay.getOrderId()); + } + errorStrBuf.append("存在重复信息,新增失败"); + } + } + + if (ObjectUtil.isNotEmpty(errorStrBuf)) { + ctDhPayExport.setError(errorStrBuf.toString()); + ctDhPayExportList.add(ctDhPayExport); + } + } + + String returnDataStr = null; + String filePath = propertiesConfig.getUploadImgPath().get(PublicConstant.EXPORT_EXCEL_FILE_TYPE); + String fileName = "敦煌支付导入异常信息表-" + snowflake.nextIdStr(); + if (ObjectUtil.isNotEmpty(ctDhPayExportList)) { + ExcelUtils.exportFile(SystemConfig.IMG_PATH + filePath, fileName, ctDhPayExportList); + returnDataStr = SystemConfig.FILE_VISIT_ADDR + filePath + fileName + ".xlsx"; + //returnDataStr = "http://localhost:8008/file" + filePath + fileName + ".xlsx"; + } + + //拆分订单编号,分多条数据存入 + if (ObjectUtil.isNotEmpty(addCtDhPayList)) { + ctDhPayService.saveBatch(addCtDhPayList); + } + + return Dto.returnResult(returnDataStr); + } + + + /** + * Excel敦煌支付信息模版导出 + * @param response + */ + @ApiOperation("Excel敦煌支付信息模版导出") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "Excel敦煌支付信息模版导出") + @GetMapping("/exportTemp") + @AnonymousAccess + public void importCard(HttpServletResponse response) { + ExcelUtils.exportTemplate(response, "敦煌支付模版", CtDhPayExportTemple.class); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtExcelController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtExcelController.java new file mode 100644 index 0000000..eaf3575 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtExcelController.java @@ -0,0 +1,157 @@ +package me.zhengjie.modules.group.controller.base; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.FormSubmission; +import me.zhengjie.annotation.Log; +import me.zhengjie.annotation.type.LogActionType; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.CtBuyer; +import me.zhengjie.entity.CtExcel; +import me.zhengjie.entity.CtExcelExportTemple; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.modules.group.dto.CtExcelAddDTO; +import me.zhengjie.modules.group.dto.CtExcelListDTO; +import me.zhengjie.modules.group.dto.CtExcelUpdateDTO; +import me.zhengjie.modules.group.dto.IdDTO; +import me.zhengjie.service.CtExcelService; +import me.zhengjie.service.vo.CtExcelVO; +import me.zhengjie.utils.PageUtils; +import me.zhengjie.utils.excel.ExcelUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + + +/** + * + * @Description Excel相关操作 控制类 + * @Date 2022-06-22 + * @Author rch + */ +@Validated +@RequestMapping("/api/ctExcel") +@RestController +@Api(tags = "业务:Excel管理") +public class CtExcelController { + + @Resource + private CtExcelService ctExcelService; + + /** + * 分页查询Excel信息 + */ + @ApiOperation("分页查询Excel信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询Excel信息") + @PostMapping("/list") + public Dto getExcelList(@Valid @RequestBody CtExcelListDTO dto) { + IPage page = ctExcelService.page(dto.getiPage(), dto.getWrapper()); + List list = new ArrayList<>(); + for (CtExcel record : page.getRecords()) { + CtExcelVO ctExcelVO = new CtExcelVO(); + BeanUtil.copyProperties(record, ctExcelVO); + list.add(ctExcelVO); + } + PageUtils pageUtils = new PageUtils(page.getTotal(),list); + return Dto.returnResult(pageUtils); + } + + /** + * 新增Excel信息 + */ + @ApiOperation("新增Excel信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "新增导入Excel信息",type = LogActionType.ADD) + @PostMapping("/add") + @FormSubmission + public Dto addExcel(@Valid @RequestBody CtExcelAddDTO dto) { + CtExcel ctExcel = new CtExcel(); + BeanUtil.copyProperties(dto, ctExcel); + return Dto.returnResult(ctExcelService.save(ctExcel)); + } + + /** + * 根据id获取Excel信息 + */ + @ApiOperation("根据id获取Excel信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据id获取Excel信息") + @PostMapping("/getById") + public Dto getExcelById(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(ctExcelService.getById(idDTO.getId())); + } + + /** + * 编辑Excel信息 + */ + @ApiOperation("编辑Excel信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3100, message = "卖家信息不存在!") + }) + @Log(value = "编辑Excel信息",type = LogActionType.UPDATE) + @PostMapping("/edit") + @FormSubmission + public Dto editExcel(@Valid @RequestBody CtExcelUpdateDTO dto) { + // 根据id 判断是否存在 + CtExcel ctExcel = ctExcelService.getById(dto.getId()); + if (ObjectUtil.isEmpty(ctExcel)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_EXCEL_USER); + } + + CtExcel updateCtExcel = new CtExcel(); + BeanUtil.copyProperties(dto, updateCtExcel); + return Dto.returnResult(ctExcelService.updateById(updateCtExcel)); + } + + /** + * 根据id删除Excel信息 + * @author: rch + */ + @ApiOperation("根据id删除Excel信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "根据id删除Excel信息",type = LogActionType.DELETE) + @PostMapping("/delete") + public Dto delExcel(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(ctExcelService.removeById(idDTO.getId())); + } + + /** + * Excel模板下载 + */ + @ApiOperation("Excel模板下载") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "Excel模板下载") + @GetMapping("/exportTemp") + public void importExcel(HttpServletResponse response){ + ExcelUtils.exportTemplate(response, "Excel导入模板", CtExcelExportTemple.class); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtExcelInfoController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtExcelInfoController.java new file mode 100644 index 0000000..9606354 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtExcelInfoController.java @@ -0,0 +1,120 @@ +package me.zhengjie.modules.group.controller.base; + +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import me.zhengjie.annotation.Log; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.CtBuyer; +import me.zhengjie.entity.CtExcelImportInfo; +import me.zhengjie.modules.group.dto.CtExcelImportInfoListDTO; +import me.zhengjie.modules.group.dto.IdDTO; +import me.zhengjie.service.CtExcelImportInfoService; +import me.zhengjie.service.vo.CtExcelImportInfoVO; +import me.zhengjie.utils.PageUtils; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + + +/** + * + * @Description Excel导入信息相关操作 控制类 + * @Date 2022-06-22 + * @Author rch + */ +@Validated +@RequestMapping("/api/ctExcelInfo") +@RestController +@Api(tags = "业务:Excel导入信息管理") +public class CtExcelInfoController { + + @Resource + private CtExcelImportInfoService ctExcelImportInfoService; + + /** + * 分页查询ExcelInfo信息 + */ + @ApiOperation("分页查询ExcelInfo信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询ExcelInfo信息") + @PostMapping("/list") + public Dto getExcelInfoList(@Valid @RequestBody CtExcelImportInfoListDTO dto) { + IPage page = ctExcelImportInfoService.page(dto.getiPage(), dto.getWrapper()); + List list = new ArrayList<>(); + for (CtExcelImportInfo record : page.getRecords()) { + CtExcelImportInfoVO ctExcelImportInfoVO = new CtExcelImportInfoVO(); + BeanUtil.copyProperties(record, ctExcelImportInfoVO); + list.add(ctExcelImportInfoVO); + } + PageUtils pageUtils = new PageUtils(page.getTotal(),list); + return Dto.returnResult(pageUtils); + } + + + /** + * 根据id获取ExcelInfo信息 + */ + @ApiOperation("根据id获取ExcelInfo信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据id获取ExcelInfo信息") + @PostMapping("/getById") + public Dto getExcelInfoById(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(ctExcelImportInfoService.getById(idDTO.getId())); + } + +// /** +// * 新增Excel信息 +// */ +// @Log(value = "新增导入Excel信息",type = LogActionType.ADD) +// @PostMapping("/add") +// public Dto addExcelInfo(@Valid @RequestBody CtExcelAddDTO dto) { +// CtExcel ctExcel = new CtExcel(); +// BeanUtil.copyProperties(dto, ctExcel); +// return Dto.returnResult(ctExcelService.save(ctExcel)); +// } + + +// /** +// * 编辑Excel信息 +// */ +// @Log(value = "编辑Excel信息",type = LogActionType.UPDATE) +// @PostMapping("/edit") +// public Dto editExcelInfo(@Valid @RequestBody CtExcelUpdateDTO dto) { +// // 根据id 判断是否存在 +// CtExcel ctExcel = ctExcelService.getById(dto.getId()); +// if (ObjectUtil.isEmpty(ctExcel)) { +// Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_EXCEL_USER); +// } +// +// CtExcel updateCtExcel = new CtExcel(); +// BeanUtil.copyProperties(dto, updateCtExcel); +// return Dto.returnResult(ctExcelService.updateById(updateCtExcel)); +// } + +// /** +// * 根据id删除Excel信息 +// * @author: rch +// */ +// @Log(value = "根据id删除Excel信息",type = LogActionType.DELETE) +// @PostMapping("/delete") +// public Dto delExcelInfo(@Valid @RequestBody IdDTO idDTO) { +// return Dto.returnResult(ctExcelService.removeById(idDTO.getId())); +// } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtOrderController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtOrderController.java new file mode 100644 index 0000000..26e7b31 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtOrderController.java @@ -0,0 +1,165 @@ +package me.zhengjie.modules.group.controller.base; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import me.zhengjie.annotation.Log; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.*; +import me.zhengjie.modules.group.dto.CtOrderListDTO; +import me.zhengjie.modules.group.dto.IdDTO; +import me.zhengjie.service.CtOrderService; +import me.zhengjie.service.CtResponseOrderAddressService; +import me.zhengjie.service.CtResponseOrderProductService; +import me.zhengjie.service.CtResponseOrderService; +import me.zhengjie.service.vo.CtOrderVO; +import me.zhengjie.service.vo.OrderResponStatusVO; +import me.zhengjie.service.vo.PayOrderVO; +import me.zhengjie.utils.PageUtils; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + + +/** + * + * @Description 群控管理- 敦煌下订单信息 控制类 + * @Date 2022-06-30 + * @Author rch + */ +@Validated +@RequestMapping("/api/dhOrder") +@RestController +@Api(tags = "业务:敦煌下单管理") +public class CtOrderController { + + @Resource + private CtOrderService ctOrderService; + @Resource + private CtResponseOrderService ctResponseOrderService; + @Resource + private CtResponseOrderAddressService ctResponseOrderAddressService; + @Resource + private CtResponseOrderProductService ctResponseOrderProductService; + + /** + * 分页查询敦煌下订单信息 + */ + @ApiOperation("分页查询敦煌下订单信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询敦煌下订单信息") + @PostMapping("/list") + public Dto getOrderList(@Valid @RequestBody CtOrderListDTO dto) { + IPage page = ctOrderService.page(dto.getiPage(), dto.getWrapper()); + List list = new ArrayList<>(); + for (CtOrder record : page.getRecords()) { + CtOrderVO ctOrderVO = new CtOrderVO(); + BeanUtil.copyProperties(record, ctOrderVO); + + // 下单状态转换 + OrderResponStatusVO orderResponStatusVO = JSONUtil.toBean(record.getOrderResponseStatus(), OrderResponStatusVO.class); + ctOrderVO.setOrderResponseStatus(orderResponStatusVO); + // 支付状态转换 + PayOrderVO payOrderVO = JSONUtil.toBean(record.getPayResponseStatus(), PayOrderVO.class); + ctOrderVO.setPayOrderVO(payOrderVO); + + list.add(ctOrderVO); + } + PageUtils pageUtils = new PageUtils(page.getTotal(),list); + return Dto.returnResult(pageUtils); + } + + /** + * 根据id获取敦煌下订单 + */ + @ApiOperation("根据id获取敦煌下订单") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据id获取敦煌下订单") + @PostMapping("/getById") + public Dto getOrderById(@Valid @RequestBody IdDTO idDTO) { + CtOrder ctOrder = ctOrderService.getById(idDTO.getId()); + if (ObjectUtil.isEmpty(ctOrder)) { + return Dto.returnResult(ctOrder); + } + CtOrderVO ctOrderVO = new CtOrderVO(); + BeanUtil.copyProperties(ctOrder, ctOrderVO); + + // 下单状态转换 + OrderResponStatusVO orderResponStatusVO = JSONUtil.toBean(ctOrder.getOrderResponseStatus(), OrderResponStatusVO.class); + ctOrderVO.setOrderResponseStatus(orderResponStatusVO); + // 支付状态转换 + PayOrderVO payOrderVO = JSONUtil.toBean(ctOrder.getPayResponseStatus(), PayOrderVO.class); + ctOrderVO.setPayOrderVO(payOrderVO); + + return Dto.returnResult(ctOrderVO); + } + + + + /** + * 根据id敦煌响应订单信息 + * @param idDTO + * @return + */ + @ApiOperation("根据id敦煌响应订单信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据id敦煌响应订单信息") + @PostMapping("/getOrderInfoById") + public Dto getOrderInfoById(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(ctResponseOrderService.getById(idDTO.getId())); + } + + + /** + * 根据id敦煌订单收件信息 + * @param idDTO + * @return + */ + @ApiOperation("根据id敦煌订单收件信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据id敦煌订单收件信息") + @PostMapping("/getOrderAddressById") + public Dto getOrderAddressById(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(ctResponseOrderAddressService.getById(idDTO.getId())); + } + + /** + * 根根据id敦煌订单产品信息 + * @param idDTO + * @return + */ + @ApiOperation("根据id敦煌订单产品信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据id敦煌订单产品信息") + @PostMapping("/getOrderProductById") + public Dto getOrderProductById(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(ctResponseOrderProductService.getById(idDTO.getId())); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtPlatformController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtPlatformController.java new file mode 100644 index 0000000..f78a278 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtPlatformController.java @@ -0,0 +1,136 @@ +//package me.zhengjie.modules.group.controller; +// +//import cn.hutool.core.bean.BeanUtil; +//import cn.hutool.core.util.ObjectUtil; +//import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +//import com.baomidou.mybatisplus.core.metadata.IPage; +//import me.zhengjie.annotation.Log; +//import me.zhengjie.annotation.type.LogActionType; +//import me.zhengjie.dto.Dto; +//import me.zhengjie.entity.CtBuyer; +//import me.zhengjie.entity.CtCompany; +//import me.zhengjie.entity.CtPlatform; +//import me.zhengjie.error.ErrorCodeEnum; +//import me.zhengjie.modules.group.dto.*; +//import me.zhengjie.service.CtCompanyService; +//import me.zhengjie.service.CtPlatformService; +//import me.zhengjie.service.vo.CtPlatformInfoVO; +//import me.zhengjie.service.vo.CtPlatformVO; +//import me.zhengjie.utils.PageUtils; +//import org.springframework.context.annotation.Bean; +//import org.springframework.validation.annotation.Validated; +//import org.springframework.web.bind.annotation.*; +// +//import javax.annotation.Resource; +//import javax.validation.Valid; +//import java.util.ArrayList; +//import java.util.List; +// +// +///** +// * +// * @Description 群控管理-平台 控制类 +// * @Date 2022-06-23 +// * @Author rch +// */ +//@Validated +//@RequestMapping("/api/ctPlatform") +//@RestController +//public class CtPlatformController { +// +// @Resource +// private CtPlatformService ctPlatformService; +// @Resource +// private CtCompanyService ctCompanyService; +// +// /** +// * 分页查询平台信息 +// */ +// @Log("分页查询平台信息") +// @PostMapping("/list") +// public Dto getPlatformList(@Valid @RequestBody CtPlatformListDTO dto) { +// IPage page = ctPlatformService.page(dto.getiPage(), dto.getWrapper()); +// List list = new ArrayList<>(); +// for (CtPlatform record : page.getRecords()) { +// CtPlatformVO ctPlatformVO = new CtPlatformVO(); +// BeanUtil.copyProperties(record, ctPlatformVO); +// list.add(ctPlatformVO); +// } +// PageUtils pageUtils = new PageUtils(page.getTotal(),list); +// return Dto.returnResult(pageUtils); +// } +// +// /** +// * 新增平台信息 +// */ +// @Log(value = "新增平台信息",type = LogActionType.ADD) +// @PostMapping("/add") +// public Dto addPlatform(@Valid @RequestBody CtPlatformAddDTO dto) { +// CtPlatform ctPlatform = new CtPlatform(); +// BeanUtil.copyProperties(dto, ctPlatform); +// return Dto.returnResult(ctPlatformService.save(ctPlatform)); +// } +// +// /** +// * 根据id平台信息详情详情 +// */ +// @Log("根据id平台信息详情详情") +// @PostMapping("/getById") +// public Dto getPlatformById(@Valid @RequestBody IdDTO idDTO) { +// return Dto.returnResult(ctPlatformService.getById(idDTO.getId())); +// } +// +// /** +// * 编辑平台信息 +// */ +// @Log(value = "编辑平台信息",type = LogActionType.UPDATE) +// @PostMapping("/edit") +// public Dto editPlatform(@Valid @RequestBody CtBuyerUpdateDTO dto) { +// // 根据id 判断是否存在 +// CtPlatform ctPlatform = ctPlatformService.getById(dto.getId()); +// if (ObjectUtil.isEmpty(ctPlatform)) { +// Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_BUYER_USER); +// } +// +// CtPlatform updateCtPlatform = new CtPlatform(); +// BeanUtil.copyProperties(dto, updateCtPlatform); +// return Dto.returnResult(ctPlatformService.updateById(updateCtPlatform)); +// } +// +// /** +// * 根据id删除平台信息 +// * @author: rch +// */ +// @Log(value = "根据id删除平台信息",type = LogActionType.DELETE) +// @PostMapping("/delete") +// public Dto delPlatform(@Valid @RequestBody IdDTO idDTO) { +// // 判断平台下有公司则不允许删除 +// QueryWrapper ctCompanyQueryWrapper = new QueryWrapper<>(); +// ctCompanyQueryWrapper.eq("platform_id", idDTO.getId()); +// Integer count = ctCompanyService.count(ctCompanyQueryWrapper); +// if (ObjectUtil.isNotEmpty(count) && count > 0) { +// Dto.getInstance(ErrorCodeEnum.ERROR_EXITS_COMPANY_INFO); +// } +// return Dto.returnResult(ctPlatformService.removeById(idDTO.getId())); +// } +// +// /** +// * 获取所有平台信息 (平台id 平台名称) +// * 为新增 公司提供公司所属平台服务 +// * @return +// */ +// @Log(value = "获取所有平台信息") +// @GetMapping("/getAll") +// public Dto allPlatform() { +// List ctPlatformList = ctPlatformService.list(); +// List ctPlatformInfoVOList = new ArrayList<>(); +// if (ObjectUtil.isNotEmpty(ctPlatformList)) { +// CtPlatformInfoVO ctPlatformInfoVO = new CtPlatformInfoVO(); +// for (CtPlatform ctPlatform:ctPlatformList) { +// BeanUtil.copyProperties(ctPlatform, ctPlatformInfoVO); +// ctPlatformInfoVOList.add(ctPlatformInfoVO); +// } +// } +// return Dto.returnResult(ctPlatformInfoVOList); +// } +//} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtRebotController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtRebotController.java new file mode 100644 index 0000000..d520076 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtRebotController.java @@ -0,0 +1,214 @@ +package me.zhengjie.modules.group.controller.base; + +import cn.hutool.core.bean.BeanUtil; +import io.swagger.annotations.*; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.FormSubmission; +import me.zhengjie.annotation.Log; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.CtRebot; +import me.zhengjie.entity.CtRebotExportTemple; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.modules.group.dto.*; +import me.zhengjie.service.CtRebotService; +import me.zhengjie.service.vo.CtRebotListVO; +import me.zhengjie.utils.PageUtils; +import me.zhengjie.utils.excel.ExcelUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * 影刀机器人(ct_rebot) 控制层 + * + * @Author zhw + * @Date 2022-07-23 + */ +@Validated +@RequestMapping("/api/ctRebot") +@RestController +@Api(tags = "业务:机器人管理") +public class CtRebotController { + + @Resource + private CtRebotService ctRebotService; + + /** + * 分页查询 影刀机器人信息 + * @param dto + * @return Dto + */ + @ApiOperation("分页查询影刀机器人信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询影刀机器人信息") + @PostMapping("/list") + public Dto getRebotList(@Valid @RequestBody CtRebotListDTO dto){ + PageUtils pageUtils = ctRebotService.searchPageList(dto.getiPage(),dto.getWrapper()); + return Dto.returnResult(pageUtils); + } + + /** + * 分页查询未占有状态机器人信息 + */ + @ApiOperation("分页查询未占有状态机器人信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询未占有状态机器人信息") + @PostMapping("freeList") + public Dto getFreeRebotList(@Valid @RequestBody CtRebotListDTO dto){ + PageUtils pageUtils = ctRebotService.searchPageList(dto.getiPage(),dto.getWrapper()); + List allRebotList = pageUtils.getList(); + List freeRebotList = new ArrayList<>(); + long freeTotal = 0L; + for(CtRebotListVO record : allRebotList){ + if(record.getStatus()==0){ + freeTotal++; + freeRebotList.add(record); + } + } + PageUtils freePageUtils = new PageUtils<>(freeTotal, freeRebotList); + return Dto.returnResult(freePageUtils); + } + + /** + * 新增影刀机器人信息 + * @param dto + * @return Dto + */ + @ApiOperation("新增影刀机器人信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("新增影刀机器人信息") + @PostMapping("/add") + @FormSubmission + public Dto addCtRebot(@Valid @RequestBody CtRebotAddDTO dto){ + CtRebot ctRebot = new CtRebot(); + BeanUtil.copyProperties(dto,ctRebot); + return Dto.returnResult(ctRebotService.save(ctRebot)); + } + + /** + * 根据ID删除影刀机器人信息 + * @param idDTO + * @return Dto + */ + @ApiOperation("根据ID删除影刀机器人信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据ID删除影刀机器人信息") + @PostMapping("/delete") + public Dto delCtRebotById(@Valid @RequestBody IdDTO idDTO){ + return Dto.returnResult(ctRebotService.removeById(idDTO.getId())); + } + + /** + * 根据ID修改影刀机器人信息 + * @param dto + * @return Dto + */ + @ApiOperation("据ID修改影刀机器人信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据ID修改影刀机器人信息") + @PostMapping("/edit") + @FormSubmission + public Dto editCtRebotById(@Valid @RequestBody CtRebotUpdateDTO dto){ + CtRebot ctRebotIsExist = ctRebotService.getById(dto.getId()); + if(ctRebotIsExist == null){ + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_REBOT); + } + CtRebot updateCtRebot = new CtRebot(); + BeanUtil.copyProperties(dto,updateCtRebot); + return Dto.returnResult(ctRebotService.updateById(updateCtRebot)); + } + + /** + * 根据Id查找影刀机器人信息 + * @param iddto + * @return Dto + */ + @ApiOperation("根据Id查找影刀机器人信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据ID查找影刀机器人信息") + @PostMapping("getById") + public Dto getById(@Valid @RequestBody IdDTO iddto){ + return Dto.returnResult(ctRebotService.getById(iddto.getId())); + } + + + /** + * TODO 这里只是测试方便使用 + * @param dto + * @return Dto + */ + @ApiOperation("重置机器人状态") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("重置机器人状态") + @PostMapping("updateStatus") + public Dto updateStatus(@Valid @RequestBody CtRebotUpdateStatusDTO dto){ + CtRebot ctRebot = new CtRebot(); + ctRebot.setId(dto.getId()); + ctRebot.setStatus(0); + return Dto.returnResult(ctRebotService.updateById(ctRebot)); + } + + /** + * EXCEL导入机器人信息 + * @param file + * @param response + * @return Dto + * @throws Exception + */ + @ApiOperation("EXCEL导入机器人信息") + @ApiImplicitParams({ + @ApiImplicitParam(value = "上传文件", name = "file", dataType = "__file", required = true) + }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("EXCEL导入机器人信息") + @PostMapping("/import") + public Dto importRebot(@RequestPart("file") MultipartFile file, HttpServletResponse response)throws Exception{ + return ctRebotService.importRebot(file, response); + } + + /** + * EXCEL导出机器人导入模板 + */ + @ApiOperation("EXCEL导出机器人导入模板") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("EXCEL导出机器人导入模板") + @GetMapping("/exportTemp") + @AnonymousAccess + public void exportRebot(HttpServletResponse response){ + ExcelUtils.exportTemplate(response, "机器人导入模板", CtRebotExportTemple.class); + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtVpnController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtVpnController.java new file mode 100644 index 0000000..9d9eab7 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/CtVpnController.java @@ -0,0 +1,261 @@ +package me.zhengjie.modules.group.controller.base; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.Snowflake; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import io.swagger.annotations.*; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.FormSubmission; +import me.zhengjie.annotation.Log; +import me.zhengjie.annotation.type.LogActionType; +import me.zhengjie.config.PropertiesConfig; +import me.zhengjie.config.SystemConfig; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.CtVpn; +import me.zhengjie.entity.CtVpnExport; +import me.zhengjie.entity.CtVpnExportTemple; +import me.zhengjie.entity.CtVpnImport; +import me.zhengjie.enums.VpnStatusEnum; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.modules.group.dto.CtVpnAddDTO; +import me.zhengjie.modules.group.dto.CtVpnListDTO; +import me.zhengjie.modules.group.dto.CtVpnUpdateDTO; +import me.zhengjie.modules.group.dto.IdDTO; +import me.zhengjie.service.CtVpnService; +import me.zhengjie.service.vo.CtVpnInfoVO; +import me.zhengjie.service.vo.CtVpnVO; +import me.zhengjie.utils.PageUtils; +import me.zhengjie.utils.excel.ExcelUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * @Description + * @Date 2022/7/7 + * @Author zhw + */ +@Validated +@RequestMapping("/api/ctVpn") +@RestController +@Api(tags = "业务:Vpn管理") +public class CtVpnController { + + @Resource + private CtVpnService ctVpnService; + @Resource + private PropertiesConfig propertiesConfig; + @Resource + private Snowflake snowflake; + + /** + * 分页查询VPN信息 + */ + @ApiOperation("分页查询VPN信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询VPN信息") + @PostMapping("/list") + public Dto getVpnList(@Valid @RequestBody CtVpnListDTO dto){ + IPage page = ctVpnService.page(dto.getiPage(),dto.getWrapper()); + List list = new ArrayList<>(); + for(CtVpn record : page.getRecords()){ + CtVpnVO ctVpnVO = new CtVpnVO(); + BeanUtil.copyProperties(record, ctVpnVO); + list.add(ctVpnVO); + } + PageUtils pageUtils = new PageUtils(page.getTotal(),list); + return Dto.returnResult(pageUtils); + } + + /** + * 新增VPN信息 + */ + @ApiOperation("新增VPN信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "新增VPN信息",type = LogActionType.ADD) + @PostMapping("/add") + @FormSubmission + public Dto addVpn(@Valid @RequestBody CtVpnAddDTO dto){ + CtVpn ctVpn = new CtVpn(); + BeanUtil.copyProperties(dto,ctVpn); + ctVpn.setStatus(VpnStatusEnum.AVAILABLE.value()); + //新增规则 + return Dto.returnResult(ctVpnService.save(ctVpn)); + } + + /** + * 根据ID查VPN详情 + */ + @ApiOperation("根据ID查VPN详情") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据ID查询VPN详情") + @PostMapping("/getById") + public Dto getVpnById(@Valid @RequestBody IdDTO idDTO){ + return Dto.returnResult(ctVpnService.getById(idDTO.getId())); + } + + /** + * 编辑VPN信息 + */ + @ApiOperation("编辑VPN信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 2000, message = "VPN信息不存在,或者已删除!") + }) + @Log(value = "编辑VPN信息",type = LogActionType.UPDATE) + @PostMapping("/edit") + @FormSubmission + public Dto editVpn(@Valid @RequestBody CtVpnUpdateDTO dto){ + //编辑规则 + //根据ID判断是否存在 + CtVpn ctVpn = ctVpnService.getById(dto.getId()); + if(ObjectUtil.isEmpty(ctVpn)){ + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_VPN); + } + + CtVpn updataCtVpn = new CtVpn(); + BeanUtil.copyProperties(dto,updataCtVpn); + return Dto.returnResult(ctVpnService.updateById(updataCtVpn)); + } + + /** + * 根据ID删除VPN信息 + */ + @ApiOperation("根据ID删除VPN信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 2000, message = "VPN信息不存在,或者已删除!") + }) + @Log(value = "根据ID删除VPN信息",type = LogActionType.DELETE) + @PostMapping("/delete") + public Dto delVpn(@Valid @RequestBody IdDTO idDTO){ + //判断删除规则 + //根据ID判断是否存在 + CtVpn ctVpn = ctVpnService.getById(idDTO.getId()); + if(ObjectUtil.isEmpty(ctVpn)){ + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_VPN); + } + return Dto.returnResult(ctVpnService.removeById(idDTO.getId())); + } + + /** + * 获取所有VPN信息 (VPNid VPN名称) + */ + @ApiOperation("获取所有VPN信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "获取所有VPN信息") + @GetMapping("/getAll") + public Dto allVpn() { + List ctVpnList = ctVpnService.list(); + List ctVpnInfoVOList = new ArrayList<>(); + if (ObjectUtil.isNotEmpty(ctVpnList)) { + for (CtVpn ctvpn:ctVpnList) { + CtVpnInfoVO ctVpnInfoVO = new CtVpnInfoVO(); + BeanUtil.copyProperties(ctvpn, ctVpnInfoVO); + ctVpnInfoVOList.add(ctVpnInfoVO); + } + } + return Dto.returnResult(ctVpnInfoVOList); + } + + /** + * EXCEL导入VPN信息 + */ + @ApiOperation("EXCEL导入VPN信息") + @ApiImplicitParams({ + @ApiImplicitParam(value = "上传文件", name = "file", dataType = "__file", required = true) + }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "EXCEL导入VPN信息",type = LogActionType.ADD) + @PostMapping("import") + public Dto importVpn(@RequestPart("file") MultipartFile file, HttpServletResponse response)throws Exception{ + + //TODO 对Excel 信息进行检测 如果不符合要求的 最终要导出错误Excel提示 + List ctVpnImportList = ExcelUtils.readMultipartFile(file,CtVpnImport.class); + if(ObjectUtil.isEmpty(ctVpnImportList)){ + return Dto.returnResult(true); + } + + List addCtVpnList = new ArrayList<>(); + List ipValueList = ctVpnService.getIpList(); + List ctVpnExportList = new ArrayList<>(); + for(CtVpnImport ctVpnImport : ctVpnImportList) { + CtVpnExport ctVpnExport = new CtVpnExport(); + BeanUtil.copyProperties(ctVpnImport, ctVpnExport); + + StringBuffer errorStrBuf = new StringBuffer(); + String rowTips = ctVpnImport.getRowTips(); + if (ObjectUtil.isNotEmpty((rowTips))) { + errorStrBuf.append(rowTips); + errorStrBuf.append(";"); + } + if (ipValueList.contains(ctVpnImport.getIpAddress())) { + errorStrBuf.append("平台已经存在该IP地址对应的VPN信息"); + } + if (ObjectUtil.isNotEmpty(errorStrBuf)) { + ctVpnExport.setError(errorStrBuf.toString()); + ctVpnExportList.add(ctVpnExport); + } else { + CtVpn ctVpn = new CtVpn(); + ctVpn.setStatus(VpnStatusEnum.AVAILABLE.value()); + BeanUtil.copyProperties(ctVpnImport, ctVpn); + addCtVpnList.add(ctVpn); + } + } + + String returnDataStr = null; + String filePath = propertiesConfig.getUploadImgPath().get(PublicConstant.EXPORT_EXCEL_FILE_TYPE); + String fileName = "VPN导入异常信息表-" + snowflake.nextIdStr(); + if(ObjectUtil.isNotEmpty(ctVpnExportList)){ + ExcelUtils.exportFile(SystemConfig.IMG_PATH + filePath, fileName, ctVpnExportList); + returnDataStr = SystemConfig.FILE_VISIT_ADDR + filePath + fileName + ".xlsx"; +// returnDataStr = "http://localhost:8008/file" + filePath + fileName + ".xlsx"; + } + + if(ObjectUtil.isNotEmpty(addCtVpnList)){ + ctVpnService.saveBatch(addCtVpnList); + } + + return Dto.returnResult(returnDataStr); + } + + /** + * Excel导出VPN导入模板 + */ + @ApiOperation("Excel导出VPN导入模板") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "Excel导出VPN导入模板") + @GetMapping("/exportTemp") + @AnonymousAccess + public void exportVpn(HttpServletResponse response) { + ExcelUtils.exportTemplate(response, "VPN导入模板", CtVpnExportTemple.class, true); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/DhAddCarCatchController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/DhAddCarCatchController.java new file mode 100644 index 0000000..224eb9b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/DhAddCarCatchController.java @@ -0,0 +1,409 @@ +package me.zhengjie.modules.group.controller.base; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.Log; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.DhAddCarOrder; +import me.zhengjie.modules.group.dto.IdDTO; +import me.zhengjie.service.DhAddCarOrderService; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.validation.Valid; + +/** + * + * @Description 群控管理-敦煌加购-抓单 控制类 + * @Date 2022-06-22 + * @Author rch + */ +@Validated +@RequestMapping("/api/dhAddCarCatch") +@RestController +@RequiredArgsConstructor +@Api(tags = "业务:敦煌加购-抓单管理") +public class DhAddCarCatchController { + + @Resource + private DhAddCarOrderService dhAddCarOrderService; + +// /** +// * 分页查询敦煌加购-抓单 +// */ +// @ApiOperation("分页查询敦煌加购-抓单") +// @ApiResponses(value = { +// @ApiResponse(code = 200, message = "响应成功"), +// @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") +// }) +// @Log("分页查询敦煌加购-抓单") +// @PostMapping("/list") +// public Dto getDhAddCardList(@Valid @RequestBody DhAddCarListDTO dto) { +// PageUtils pageUtilsResult = dhAddCarService.searchPageList(dto.getiPage(), dto.getWrapper()); +// return Dto.returnResult(pageUtilsResult); +// } + +// /** +// * 新增敦煌加购-抓单 +// */ +// @ApiOperation("新增敦煌加购-抓单") +// @ApiResponses(value = { +// @ApiResponse(code = 200, message = "响应成功"), +// @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") +// }) +// @Log(value = "新增敦煌加购-抓单",type = LogActionType.ADD) +// @PostMapping("/add") +// @FormSubmission +// public Dto addDhCar(@Valid @RequestBody DhAddCarAddDTO dto) { +// +// Integer paramsType = dto.getParamsType(); +// List dhCarGoodList = new ArrayList<>(); +// if (ParamsTypeEnum.KEY_WORD.eqValue(paramsType)) { +// List DhCarGoodKeyList = dto.getCarGoodKeys(); +// if (ObjectUtil.isEmpty(DhCarGoodKeyList)) { +// return Dto.getInstance(ErrorCodeEnum.ERROR_ADD_CAR_KEY_NULL); +// } else { +// for (DhCarGoodKeyAddDTO dhCarGoodKeyDTO:DhCarGoodKeyList) { +// DhCarGoods dhCarGoods = new DhCarGoods(); +// BeanUtil.copyProperties(dhCarGoodKeyDTO, dhCarGoods); +// dhCarGoodList.add(dhCarGoods); +// } +// } +// } else if (ParamsTypeEnum.LINK.eqValue(paramsType)) { +// List DhCarGoodLinkList = dto.getCarGoodLinks(); +// if (ObjectUtil.isEmpty(DhCarGoodLinkList)) { +// return Dto.getInstance(ErrorCodeEnum.ERROR_ADD_CAR_LINK_NULL); +// } else { +// for (DhCarGoodLinkAddDTO dhCarGoodLinkDTO:DhCarGoodLinkList) { +// DhCarGoods dhCarGoods = new DhCarGoods(); +// BeanUtil.copyProperties(dhCarGoodLinkDTO, dhCarGoods); +// dhCarGoodList.add(dhCarGoods); +// } +// } +// } else { +// return Dto.getInstance(ErrorCodeEnum.ERROR_ADD_CAR_GOODS_NULL); +// } +// +// // service 层 分别存储两个表信息 +// Boolean resultBoolean = dhCarGoodsService.saveBatch(dhCarGoodList); +// if (resultBoolean) { +// List goodsIdList = dhCarGoodList.stream().map(DhCarGoods::getId).collect(Collectors.toList()); +// +// DhAddCar dhAddCar = new DhAddCar(); +// BeanUtil.copyProperties(dto, dhAddCar); +// dhAddCar.setCarGoodIds(Joiner.on(",").join(goodsIdList)); +// resultBoolean = dhAddCarService.save(dhAddCar); +// } +// +// return Dto.returnResult(resultBoolean); +// } + + /** + * 根据id获取刷单信息 + */ + @ApiOperation("根据id获取刷单信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据id获取刷单信息") + @PostMapping("/getById") + public Dto getById(@Valid @RequestBody IdDTO idDTO) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("add_car_id", idDTO.getId()); + return Dto.returnResult(dhAddCarOrderService.getOne(queryWrapper)); + } + +// /** +// * 根据id获取修改回显信息 +// */ +// @ApiOperation("根据id获取修改回显信息") +// @ApiResponses(value = { +// @ApiResponse(code = 200, message = "响应成功"), +// @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") +// }) +// @Log("根据id获取修改回显信息") +// @PostMapping("/getEditDetailById") +// public Dto getEditDetailById(@Valid @RequestBody IdDTO idDTO) { +// return Dto.returnResult(dhAddCarService.getDetailById(idDTO.getId())); +// } +// +// /** +// * 根据id删除刷单信息 +// * @author: rch +// */ +// @ApiOperation("根据id删除敦煌加购-抓单") +// @ApiResponses(value = { +// @ApiResponse(code = 200, message = "响应成功"), +// @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), +// @ApiResponse(code = 4404, message = "敦煌加购-抓单信息不存在,或者已删除或异常!"), +// @ApiResponse(code = 3901, message = "只有待执行的刷单信息才允许删除!") +// }) +// @Log(value = "根据id删除刷单信息",type = LogActionType.DELETE) +// @PostMapping("/delete") +// public Dto delClickFarming(@Valid @RequestBody IdDTO idDTO) { +// +// // 先查询 +// DhAddCar dhAddCar = dhAddCarService.getById(idDTO.getId()); +// if (ObjectUtil.isEmpty(dhAddCar)) { +// return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_ADD_CAR_INFO); +// } +// +// if (!DhAddCarStatusEnum.TOBE_EXECUTION.eqValue(dhAddCar.getStatus())) { +// return Dto.getInstance(ErrorCodeEnum.ERROR_DEL_ADD_CAR_INFO); +// } +// +// Boolean resultBoolean = false; +// if (dhAddCarService.removeById(idDTO.getId())) { +// String goodIds = dhAddCar.getCarGoodIds(); +// List goodIdList = new ArrayList<>(); +// if (goodIds.contains(",")){ +// goodIdList = Arrays.asList(goodIds.split(",")).stream().map(s -> Long.parseLong(s.trim())).collect(Collectors.toList()); +// }else { +// goodIdList.add(Long.valueOf(goodIds)); +// } +// resultBoolean = dhCarGoodsService.removeByIds(goodIdList); +// } +// +// return Dto.returnResult(resultBoolean); +// } +// +// /** +// * 编辑刷单信息 +// */ +// @ApiOperation("编辑敦煌加购-抓单") +// @ApiResponses(value = { +// @ApiResponse(code = 200, message = "响应成功"), +// @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), +// @ApiResponse(code = 4404, message ="敦煌加购-抓单信息不存在!") +// }) +// @Log(value = "编辑敦煌加购-抓单",type = LogActionType.UPDATE) +// @PostMapping("/edit") +// @FormSubmission +// public Dto editDhAddCar(@Valid @RequestBody DhAddCarEditDTO dto) { +// +// DhAddCar dhAddCar = dhAddCarService.getById(dto.getId()); +// if (ObjectUtil.isEmpty(dhAddCar)) { +// return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_ADD_CAR_INFO); +// } +// +// if (!DhAddCarStatusEnum.TOBE_EXECUTION.eqValue(dhAddCar.getStatus())) { +// return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_EDIT_ADD_CAR_INFO); +// } +// +// // 关键词 +// BeanUtil.copyProperties(dto, dhAddCar); +// List dhCarGoodList = new ArrayList<>(); +// Boolean result = false; +// if (ParamsTypeEnum.KEY_WORD.value().equals(dto.getParamsType())) { +// List carGoodKeys = dto.getCarGoodKeys(); +// for (DhCarGoodKeyEditDTO dhCarGoodKeyEditDTO:carGoodKeys) { +// DhCarGoods dhCarGoods = new DhCarGoods(); +// BeanUtil.copyProperties(dhCarGoodKeyEditDTO, dhCarGoods); +// dhCarGoodList.add(dhCarGoods); +// } +// } +// // 链接 +// if (ParamsTypeEnum.LINK.value().equals(dto.getParamsType())) { +// List carGoodLinks = dto.getCarGoodLinks(); +// for (DhCarGoodLinkEditDTO dhCarGoodLinkEditDTO:carGoodLinks) { +// DhCarGoods dhCarGoods = new DhCarGoods(); +// BeanUtil.copyProperties(dhCarGoodLinkEditDTO, dhCarGoods); +// dhCarGoodList.add(dhCarGoods); +// } +// } +// if (ObjectUtil.isNotEmpty(dhCarGoodList)) { +// if (dhCarGoodsService.saveOrUpdateBatch(dhCarGoodList)) { +// String dhCarGoodIdStr = Joiner.on(",").join(dhCarGoodList.stream().map(DhCarGoods::getId).collect(Collectors.toList())); +// dhAddCar.setCarGoodIds(dhCarGoodIdStr); +// result = dhAddCarService.updateById(dhAddCar); +// } +// } +// +// return Dto.returnResult(result); +// } +// +// +// /** +// * 下单成功(加购-抓单成功状态 手动转下单成功) +// * @param idDTO +// * @return +// */ +// @ApiOperation("下单成功") +// @ApiResponses(value = { +// @ApiResponse(code = 200, message = "响应成功"), +// @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), +// @ApiResponse(code = 4404, message ="敦煌加购-抓单信息不存在!") +// }) +// @Log(value = "下单成功",type = LogActionType.UPDATE) +// @PostMapping("/orderSuccess") +// @FormSubmission +// public Dto orderSuccess(@Valid @RequestBody IdDTO idDTO) { +// DhAddCar dhAddCar = dhAddCarService.getByIdLock(idDTO.getId()); +// if (ObjectUtil.isEmpty(dhAddCar)) { +// return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_ADD_CAR_INFO); +// } +// +// DhAddCar updateDhAddCar = new DhAddCar(); +// updateDhAddCar.setId(dhAddCar.getId()); +// updateDhAddCar.setStatus(DhAddCarStatusEnum.ORDER_SUCCESS.value()); +// return Dto.returnResult(dhAddCarService.updateById(updateDhAddCar)); +// } +// +// /** +// * 支付成功(下单成功状态 手动转支付成功) +// * @param idDTO +// * @return +// */ +// @ApiOperation("支付成功") +// @ApiResponses(value = { +// @ApiResponse(code = 200, message = "响应成功"), +// @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), +// @ApiResponse(code = 4404, message ="敦煌加购-抓单信息不存在!") +// }) +// @Log(value = "支付成功",type = LogActionType.UPDATE) +// @PostMapping("/toBeCatch") +// @FormSubmission +// public Dto toBeCatch(@Valid @RequestBody IdDTO idDTO) { +// DhAddCar dhAddCar = dhAddCarService.getByIdLock(idDTO.getId()); +// if (ObjectUtil.isEmpty(dhAddCar)) { +// return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_ADD_CAR_INFO); +// } +// +// DhAddCar updateDhAddCar = new DhAddCar(); +// updateDhAddCar.setId(dhAddCar.getId()); +// updateDhAddCar.setStatus(DhAddCarStatusEnum.TO_BE_CATCH_ORDER.value()); +// return Dto.returnResult(dhAddCarService.updateById(updateDhAddCar)); +// } + +// +// /** +// * +// * @param file +// * @param response +// * @return +// * @throws Exception +// */ +// @ApiOperation("Excel刷单信息导入") +// @ApiImplicitParams({ +// @ApiImplicitParam(value = "上传文件", name = "file", dataType = "__file", required = true) +// }) +// @ApiResponses(value = { +// @ApiResponse(code = 200, message = "响应成功"), +// @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") +// }) +// @Log(value = "Excel刷单信息导入",type = LogActionType.ADD) +// @PostMapping("/import") +// public Dto importClickFarming(@RequestPart("file")MultipartFile file, HttpServletResponse response) throws Exception { +// +// // TODO 对Excel 信息进行检测 如果不符合要求的 最终要导出错误Excel提示 +// List ctClickFarmingImportList = ExcelUtils.readMultipartFile(file, CtClickFarmingImport.class); +// if (ObjectUtil.isEmpty(ctClickFarmingImportList)) { +// return Dto.returnResult(true); +// } +// +// List addCtClickFarmingList = new ArrayList<>(); +// List ctClickFarmingExportList = new ArrayList<>(); +// +// // 买家id +// List buyerAccountList = ctClickFarmingImportList.stream().map(c->c.getAccount()).collect(Collectors.toList()); +// Map buyerMap = ctBuyerService.getBuyerList(buyerAccountList); +// +// for (CtClickFarmingImport ctClickFarmingImport:ctClickFarmingImportList) { +// CtClickFarmingExport ctClickFarmingExport = new CtClickFarmingExport(); +// BeanUtil.copyProperties(ctClickFarmingImport, ctClickFarmingExport); +// +// StringBuffer errorStrBuf = new StringBuffer(); +// String rowTips = ctClickFarmingImport.getRowTips(); +// if (ObjectUtil.isNotEmpty(rowTips)) { +// errorStrBuf.append(rowTips); +// errorStrBuf.append(";"); +// } +// +// if (ObjectUtil.isEmpty(ctClickFarmingImport.getSpecification())) { +// errorStrBuf.append("规格-必填!"); +// errorStrBuf.append(";"); +// } +// if (ObjectUtil.isEmpty(ctClickFarmingImport.getColor())) { +// errorStrBuf.append("颜色-必填!"); +// errorStrBuf.append(";"); +// } +// if (ObjectUtil.isEmpty(ctClickFarmingImport.getExchange())) { +// errorStrBuf.append("优惠劵-必填!"); +// errorStrBuf.append(";"); +// } +// +// // 判断类型 +// if (ParamsTypeEnum.KEY_WORD.eqValue(ctClickFarmingImport.getParamsType())) { +// if (ObjectUtil.isEmpty(ctClickFarmingImport.getKeyWord())) { +// errorStrBuf.append("关键词-必填!"); +// errorStrBuf.append(";"); +// } +// if (ObjectUtil.isEmpty(ctClickFarmingImport.getTitle())) { +// errorStrBuf.append("标题-必填!"); +// errorStrBuf.append(";"); +// } +// if (ObjectUtil.isEmpty(ctClickFarmingImport.getItem())) { +// errorStrBuf.append("item-必填!"); +// errorStrBuf.append(";"); +// } +// } else { +// if (ObjectUtil.isEmpty(ctClickFarmingImport.getLink())) { +// errorStrBuf.append("链接-必填!"); +// errorStrBuf.append(";"); +// } +// } +// +// if (ObjectUtil.isEmpty(buyerMap) || !buyerMap.containsKey(ctClickFarmingImport.getAccount())) { +// errorStrBuf.append("买家信息不存在!"); +// errorStrBuf.append(";"); +// } else { +// Long buyerId = buyerMap.entrySet().stream().collect(Collectors.toMap(entity -> entity.getKey(), entity -> entity.getValue())).get(ctClickFarmingImport.getAccount()).getId(); +// ctClickFarmingImport.setBuyerId(buyerId); +// } +// if (ObjectUtil.isNotEmpty(errorStrBuf)) { +// ctClickFarmingExport.setError(errorStrBuf.toString()); +// ctClickFarmingExportList.add(ctClickFarmingExport); +// } else { +// CtClickFarming ctClickFarming = new CtClickFarming(); +// BeanUtils.copyProperties(ctClickFarmingImport, ctClickFarming); +// addCtClickFarmingList.add(ctClickFarming); +// } +// } +// +// String returnDataStr = null; +// String filePath = propertiesConfig.getUploadImgPath().get(PublicConstant.EXPORT_EXCEL_FILE_TYPE); +// String fileName = "刷单信息导入异常信息表-" + snowflake.nextIdStr(); +// if (ObjectUtil.isNotEmpty(ctClickFarmingExportList)) { +// ExcelUtils.exportFile(SystemConfig.IMG_PATH + filePath, fileName, ctClickFarmingExportList); +// returnDataStr = SystemConfig.FILE_VISIT_ADDR + filePath + fileName + ".xlsx"; +//// returnDataStr = "http://localhost:8008/file" + filePath + fileName + ".xlsx"; +// } +// +// if (ObjectUtil.isNotEmpty(addCtClickFarmingList)) { +// ctClickFarmingService.saveBatch(addCtClickFarmingList); +// } +// +// return Dto.returnResult(returnDataStr); +// } +// +// @ApiOperation("Excel刷单信息模版导出") +// @ApiResponses(value = { +// @ApiResponse(code = 200, message = "响应成功"), +// @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") +// }) +// @Log(value = "Excel刷单信息模版导出") +// @GetMapping("/exportTemp") +// @AnonymousAccess +// public void importClickFarming(HttpServletResponse response) { +// ExcelUtils.exportTemplate(response, "刷单信息模版", CtClickFarmingExportTemp.class); +// } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/DhAddCarController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/DhAddCarController.java new file mode 100644 index 0000000..dfc9a72 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/DhAddCarController.java @@ -0,0 +1,466 @@ +package me.zhengjie.modules.group.controller.base; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import com.google.common.base.Joiner; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.FormSubmission; +import me.zhengjie.annotation.Log; +import me.zhengjie.annotation.type.LogActionType; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.DhAddCar; +import me.zhengjie.entity.DhCarGoods; +import me.zhengjie.enums.DhAddCarStatusEnum; +import me.zhengjie.enums.ParamsTypeEnum; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.modules.group.dto.DhCarWellReceivedDTO; +import me.zhengjie.modules.group.dto.IdDTO; +import me.zhengjie.modules.group.dto.DhCarGoodWellReceivedDTO; +import me.zhengjie.modules.group.dto.dhaddcar.DhAddCarAddDTO; +import me.zhengjie.modules.group.dto.dhaddcar.DhAddCarEditDTO; +import me.zhengjie.modules.group.dto.dhaddcar.DhAddCarListDTO; +import me.zhengjie.modules.group.dto.dhcargood.*; +import me.zhengjie.service.DhAddCarService; +import me.zhengjie.service.DhCarGoodsService; +import me.zhengjie.service.vo.dhaddcar.DhAddCarListVO; +import me.zhengjie.service.vo.dhaddcar.DhAddCarVO; +import me.zhengjie.utils.PageUtils; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * + * @Description 群控管理-敦煌加购 控制类 + * @Date 2022-06-22 + * @Author rch + */ +@Validated +@RequestMapping("/api/dhAddCar") +@RestController +@RequiredArgsConstructor +@Api(tags = "业务:敦煌加购管理") +public class DhAddCarController { + + @Resource + private DhCarGoodsService dhCarGoodsService; + @Resource + private DhAddCarService dhAddCarService; + + /** + * 分页查询敦煌加购 + */ + @ApiOperation("分页查询敦煌加购") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询敦煌加购") + @PostMapping("/list") + public Dto getDhAddCardList(@Valid @RequestBody DhAddCarListDTO dto) { + PageUtils pageUtilsResult = dhAddCarService.searchPageList(dto.getiPage(), dto.getWrapper()); + return Dto.returnResult(pageUtilsResult); + } + + /** + * 新增敦煌加购 + */ + @ApiOperation("新增敦煌加购") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log(value = "新增敦煌加购",type = LogActionType.ADD) + @PostMapping("/add") + @FormSubmission + public Dto addDhCar(@Valid @RequestBody DhAddCarAddDTO dto) { + + Integer paramsType = dto.getParamsType(); + List dhCarGoodList = new ArrayList<>(); + if (ParamsTypeEnum.KEY_WORD.eqValue(paramsType)) { + List DhCarGoodKeyList = dto.getCarGoodKeys(); + if (ObjectUtil.isEmpty(DhCarGoodKeyList)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_ADD_CAR_KEY_NULL); + } else { + for (DhCarGoodKeyAddDTO dhCarGoodKeyDTO:DhCarGoodKeyList) { + DhCarGoods dhCarGoods = new DhCarGoods(); + BeanUtil.copyProperties(dhCarGoodKeyDTO, dhCarGoods); + dhCarGoodList.add(dhCarGoods); + } + } + } else if (ParamsTypeEnum.LINK.eqValue(paramsType)) { + List DhCarGoodLinkList = dto.getCarGoodLinks(); + if (ObjectUtil.isEmpty(DhCarGoodLinkList)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_ADD_CAR_LINK_NULL); + } else { + for (DhCarGoodLinkAddDTO dhCarGoodLinkDTO:DhCarGoodLinkList) { + DhCarGoods dhCarGoods = new DhCarGoods(); + BeanUtil.copyProperties(dhCarGoodLinkDTO, dhCarGoods); + dhCarGoodList.add(dhCarGoods); + } + } + } else { + return Dto.getInstance(ErrorCodeEnum.ERROR_ADD_CAR_GOODS_NULL); + } + + // service 层 分别存储两个表信息 + Boolean resultBoolean = dhCarGoodsService.saveBatch(dhCarGoodList); + if (resultBoolean) { + List goodsIdList = dhCarGoodList.stream().map(DhCarGoods::getId).collect(Collectors.toList()); + + DhAddCar dhAddCar = new DhAddCar(); + BeanUtil.copyProperties(dto, dhAddCar); + dhAddCar.setCarGoodIds(Joiner.on(",").join(goodsIdList)); + resultBoolean = dhAddCarService.save(dhAddCar); + } + + return Dto.returnResult(resultBoolean); + } + +// /** +// * 根据id获取刷单信息 +// */ +// @ApiOperation("根据id获取刷单信息") +// @ApiResponses(value = { +// @ApiResponse(code = 200, message = "响应成功"), +// @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") +// }) +// @Log("根据id获取刷单信息") +// @PostMapping("/getById") +// public Dto getById(@Valid @RequestBody IdDTO idDTO) { +// return Dto.returnResult(ctClickFarmingService.getDetailById(idDTO.getId())); +// } +// + /** + * 根据id获取修改回显信息 + */ + @ApiOperation("根据id获取修改回显信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据id获取修改回显信息") + @PostMapping("/getEditDetailById") + public Dto getEditDetailById(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(dhAddCarService.getDetailById(idDTO.getId())); + } + + /** + * 根据id删除刷单信息 + * @author: rch + */ + @ApiOperation("根据id删除敦煌加购") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 4404, message = "敦煌加购信息不存在,或者已删除或异常!"), + @ApiResponse(code = 3901, message = "只有待执行的刷单信息才允许删除!") + }) + @Log(value = "根据id删除刷单信息",type = LogActionType.DELETE) + @PostMapping("/delete") + public Dto delClickFarming(@Valid @RequestBody IdDTO idDTO) { + + // 先查询 + DhAddCar dhAddCar = dhAddCarService.getById(idDTO.getId()); + if (ObjectUtil.isEmpty(dhAddCar)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_ADD_CAR_INFO); + } + + if (!DhAddCarStatusEnum.TOBE_EXECUTION.eqValue(dhAddCar.getStatus())) { + return Dto.getInstance(ErrorCodeEnum.ERROR_DEL_ADD_CAR_INFO); + } + + Boolean resultBoolean = false; + if (dhAddCarService.removeById(idDTO.getId())) { + String goodIds = dhAddCar.getCarGoodIds(); + List goodIdList = new ArrayList<>(); + if (goodIds.contains(",")){ + goodIdList = Arrays.asList(goodIds.split(",")).stream().map(s -> Long.parseLong(s.trim())).collect(Collectors.toList()); + }else { + goodIdList.add(Long.valueOf(goodIds)); + } + resultBoolean = dhCarGoodsService.removeByIds(goodIdList); + } + + return Dto.returnResult(resultBoolean); + } + + /** + * 编辑刷单信息 + */ + @ApiOperation("编辑敦煌加购") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 4404, message ="敦煌加购信息不存在!") + }) + @Log(value = "编辑敦煌加购",type = LogActionType.UPDATE) + @PostMapping("/edit") + @FormSubmission + public Dto editDhAddCar(@Valid @RequestBody DhAddCarEditDTO dto) { + + DhAddCar dhAddCar = dhAddCarService.getById(dto.getId()); + if (ObjectUtil.isEmpty(dhAddCar)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_ADD_CAR_INFO); + } + + if (!DhAddCarStatusEnum.TOBE_EXECUTION.eqValue(dhAddCar.getStatus())) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_EDIT_ADD_CAR_INFO); + } + + // 关键词 + BeanUtil.copyProperties(dto, dhAddCar); + List dhCarGoodList = new ArrayList<>(); + Boolean result = false; + if (ParamsTypeEnum.KEY_WORD.value().equals(dto.getParamsType())) { + List carGoodKeys = dto.getCarGoodKeys(); + for (DhCarGoodKeyEditDTO dhCarGoodKeyEditDTO:carGoodKeys) { + DhCarGoods dhCarGoods = new DhCarGoods(); + BeanUtil.copyProperties(dhCarGoodKeyEditDTO, dhCarGoods); + dhCarGoodList.add(dhCarGoods); + } + } + // 链接 + if (ParamsTypeEnum.LINK.value().equals(dto.getParamsType())) { + List carGoodLinks = dto.getCarGoodLinks(); + for (DhCarGoodLinkEditDTO dhCarGoodLinkEditDTO:carGoodLinks) { + DhCarGoods dhCarGoods = new DhCarGoods(); + BeanUtil.copyProperties(dhCarGoodLinkEditDTO, dhCarGoods); + dhCarGoodList.add(dhCarGoods); + } + } + if (ObjectUtil.isNotEmpty(dhCarGoodList)) { + if (dhCarGoodsService.saveOrUpdateBatch(dhCarGoodList)) { + String dhCarGoodIdStr = Joiner.on(",").join(dhCarGoodList.stream().map(DhCarGoods::getId).collect(Collectors.toList())); + dhAddCar.setCarGoodIds(dhCarGoodIdStr); + result = dhAddCarService.updateById(dhAddCar); + } + } + + return Dto.returnResult(result); + } + + + /** + * 下单成功(加购成功状态 手动转下单成功) + * @param idDTO + * @return + */ + @ApiOperation("下单成功") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 4404, message ="敦煌加购信息不存在!") + }) + @Log(value = "下单成功",type = LogActionType.UPDATE) + @PostMapping("/orderSuccess") + @FormSubmission + public Dto orderSuccess(@Valid @RequestBody IdDTO idDTO) { + DhAddCar dhAddCar = dhAddCarService.getByIdLock(idDTO.getId()); + if (ObjectUtil.isEmpty(dhAddCar)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_ADD_CAR_INFO); + } + + DhAddCar updateDhAddCar = new DhAddCar(); + updateDhAddCar.setId(dhAddCar.getId()); + updateDhAddCar.setStatus(DhAddCarStatusEnum.ORDER_SUCCESS.value()); + return Dto.returnResult(dhAddCarService.updateById(updateDhAddCar)); + } + + /** + * 支付成功(下单成功状态 手动转支付成功) + * @param idDTO + * @return + */ + @ApiOperation("支付成功") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 4404, message ="敦煌加购信息不存在!") + }) + @Log(value = "支付成功",type = LogActionType.UPDATE) + @PostMapping("/toBeCatch") + @FormSubmission + public Dto toBeCatch(@Valid @RequestBody IdDTO idDTO) { + DhAddCar dhAddCar = dhAddCarService.getByIdLock(idDTO.getId()); + if (ObjectUtil.isEmpty(dhAddCar)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_ADD_CAR_INFO); + } + + DhAddCar updateDhAddCar = new DhAddCar(); + updateDhAddCar.setId(dhAddCar.getId()); + updateDhAddCar.setStatus(DhAddCarStatusEnum.TO_BE_CATCH_ORDER.value()); + return Dto.returnResult(dhAddCarService.updateById(updateDhAddCar)); + } + + /** + * 好评 + * @param dto + * @return + */ + @ApiOperation("好评") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 4404, message ="敦煌加购信息不存在!") + }) + @Log(value = "好评",type = LogActionType.UPDATE) + @PostMapping("/wellReceive") + @FormSubmission + public Dto wellReceived(@Valid @RequestBody DhCarWellReceivedDTO dto) { + + + DhAddCar dhAddCar = dhAddCarService.getByIdLock(dto.getId()); + if (ObjectUtil.isEmpty(dhAddCar)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_ADD_CAR_INFO); + } + + if (!DhAddCarStatusEnum.CATCH_ORDER_SUCCESS.eqValue(dhAddCar.getStatus())) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_WELL_RECEIVED_ADD_CAR_INFO); + } + + List goods = dto.getDialogWellReceivedGoods(); + List dhCarGoodsList = new ArrayList<>(); + for (DhCarGoodWellReceivedDTO good :goods) { + DhCarGoods dhCarGoods = new DhCarGoods(); + BeanUtil.copyProperties(good, dhCarGoods); + dhCarGoodsList.add(dhCarGoods); + } + return Dto.returnResult(dhCarGoodsService.updateBatchById(dhCarGoodsList)); + } +// +// /** +// * +// * @param file +// * @param response +// * @return +// * @throws Exception +// */ +// @ApiOperation("Excel刷单信息导入") +// @ApiImplicitParams({ +// @ApiImplicitParam(value = "上传文件", name = "file", dataType = "__file", required = true) +// }) +// @ApiResponses(value = { +// @ApiResponse(code = 200, message = "响应成功"), +// @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") +// }) +// @Log(value = "Excel刷单信息导入",type = LogActionType.ADD) +// @PostMapping("/import") +// public Dto importClickFarming(@RequestPart("file")MultipartFile file, HttpServletResponse response) throws Exception { +// +// // TODO 对Excel 信息进行检测 如果不符合要求的 最终要导出错误Excel提示 +// List ctClickFarmingImportList = ExcelUtils.readMultipartFile(file, CtClickFarmingImport.class); +// if (ObjectUtil.isEmpty(ctClickFarmingImportList)) { +// return Dto.returnResult(true); +// } +// +// List addCtClickFarmingList = new ArrayList<>(); +// List ctClickFarmingExportList = new ArrayList<>(); +// +// // 买家id +// List buyerAccountList = ctClickFarmingImportList.stream().map(c->c.getAccount()).collect(Collectors.toList()); +// Map buyerMap = ctBuyerService.getBuyerList(buyerAccountList); +// +// for (CtClickFarmingImport ctClickFarmingImport:ctClickFarmingImportList) { +// CtClickFarmingExport ctClickFarmingExport = new CtClickFarmingExport(); +// BeanUtil.copyProperties(ctClickFarmingImport, ctClickFarmingExport); +// +// StringBuffer errorStrBuf = new StringBuffer(); +// String rowTips = ctClickFarmingImport.getRowTips(); +// if (ObjectUtil.isNotEmpty(rowTips)) { +// errorStrBuf.append(rowTips); +// errorStrBuf.append(";"); +// } +// +// if (ObjectUtil.isEmpty(ctClickFarmingImport.getSpecification())) { +// errorStrBuf.append("规格-必填!"); +// errorStrBuf.append(";"); +// } +// if (ObjectUtil.isEmpty(ctClickFarmingImport.getColor())) { +// errorStrBuf.append("颜色-必填!"); +// errorStrBuf.append(";"); +// } +// if (ObjectUtil.isEmpty(ctClickFarmingImport.getExchange())) { +// errorStrBuf.append("优惠劵-必填!"); +// errorStrBuf.append(";"); +// } +// +// // 判断类型 +// if (ParamsTypeEnum.KEY_WORD.eqValue(ctClickFarmingImport.getParamsType())) { +// if (ObjectUtil.isEmpty(ctClickFarmingImport.getKeyWord())) { +// errorStrBuf.append("关键词-必填!"); +// errorStrBuf.append(";"); +// } +// if (ObjectUtil.isEmpty(ctClickFarmingImport.getTitle())) { +// errorStrBuf.append("标题-必填!"); +// errorStrBuf.append(";"); +// } +// if (ObjectUtil.isEmpty(ctClickFarmingImport.getItem())) { +// errorStrBuf.append("item-必填!"); +// errorStrBuf.append(";"); +// } +// } else { +// if (ObjectUtil.isEmpty(ctClickFarmingImport.getLink())) { +// errorStrBuf.append("链接-必填!"); +// errorStrBuf.append(";"); +// } +// } +// +// if (ObjectUtil.isEmpty(buyerMap) || !buyerMap.containsKey(ctClickFarmingImport.getAccount())) { +// errorStrBuf.append("买家信息不存在!"); +// errorStrBuf.append(";"); +// } else { +// Long buyerId = buyerMap.entrySet().stream().collect(Collectors.toMap(entity -> entity.getKey(), entity -> entity.getValue())).get(ctClickFarmingImport.getAccount()).getId(); +// ctClickFarmingImport.setBuyerId(buyerId); +// } +// if (ObjectUtil.isNotEmpty(errorStrBuf)) { +// ctClickFarmingExport.setError(errorStrBuf.toString()); +// ctClickFarmingExportList.add(ctClickFarmingExport); +// } else { +// CtClickFarming ctClickFarming = new CtClickFarming(); +// BeanUtils.copyProperties(ctClickFarmingImport, ctClickFarming); +// addCtClickFarmingList.add(ctClickFarming); +// } +// } +// +// String returnDataStr = null; +// String filePath = propertiesConfig.getUploadImgPath().get(PublicConstant.EXPORT_EXCEL_FILE_TYPE); +// String fileName = "刷单信息导入异常信息表-" + snowflake.nextIdStr(); +// if (ObjectUtil.isNotEmpty(ctClickFarmingExportList)) { +// ExcelUtils.exportFile(SystemConfig.IMG_PATH + filePath, fileName, ctClickFarmingExportList); +// returnDataStr = SystemConfig.FILE_VISIT_ADDR + filePath + fileName + ".xlsx"; +//// returnDataStr = "http://localhost:8008/file" + filePath + fileName + ".xlsx"; +// } +// +// if (ObjectUtil.isNotEmpty(addCtClickFarmingList)) { +// ctClickFarmingService.saveBatch(addCtClickFarmingList); +// } +// +// return Dto.returnResult(returnDataStr); +// } +// +// @ApiOperation("Excel刷单信息模版导出") +// @ApiResponses(value = { +// @ApiResponse(code = 200, message = "响应成功"), +// @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") +// }) +// @Log(value = "Excel刷单信息模版导出") +// @GetMapping("/exportTemp") +// @AnonymousAccess +// public void importClickFarming(HttpServletResponse response) { +// ExcelUtils.exportTemplate(response, "刷单信息模版", CtClickFarmingExportTemp.class); +// } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/DhAddCarOrderController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/DhAddCarOrderController.java new file mode 100644 index 0000000..0617e82 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/DhAddCarOrderController.java @@ -0,0 +1,57 @@ +package me.zhengjie.modules.group.controller.base; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.Log; +import me.zhengjie.dto.Dto; +import me.zhengjie.modules.group.dto.dhaddcar.DhAddCarListDTO; +import me.zhengjie.modules.group.dto.dhcarorder.DhAddCarOrderListDTO; +import me.zhengjie.service.DhAddCarOrderService; +import me.zhengjie.service.DhAddCarService; +import me.zhengjie.service.DhCarGoodsService; +import me.zhengjie.service.vo.dhaddcar.DhAddCarListVO; +import me.zhengjie.service.vo.dhcarorder.DhAddCarOrderListVO; +import me.zhengjie.utils.PageUtils; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.validation.Valid; + +/** + * + * @Description 群控管理-敦煌加购-订单 控制类 + * @Date 2022-06-22 + * @Author rch + */ +@Validated +@RequestMapping("/api/dhAddCarOrder") +@RestController +@RequiredArgsConstructor +@Api(tags = "业务:敦煌加购订单管理") +public class DhAddCarOrderController { + + @Resource + private DhAddCarOrderService dhAddCarOrderService; + + /** + * 分页查询敦煌加购 + */ + @ApiOperation("分页查询敦煌加购") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询敦煌加购") + @PostMapping("/list") + public Dto getDhAddCardList(@Valid @RequestBody DhAddCarOrderListDTO dto) { + PageUtils pageUtilsResult = dhAddCarOrderService.searchPageList(dto.getiPage(), dto.getWrapper()); + return Dto.returnResult(pageUtilsResult); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/QuartzLogController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/QuartzLogController.java new file mode 100644 index 0000000..5f3ed6c --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/QuartzLogController.java @@ -0,0 +1,55 @@ +package me.zhengjie.modules.group.controller.base; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.Log; +import me.zhengjie.dto.Dto; +import me.zhengjie.modules.group.dto.SysQuartzLogListDTO; +import me.zhengjie.service.SysQuartzLogService; +import me.zhengjie.service.vo.SysQuartzLogListVO; +import me.zhengjie.utils.PageUtils; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.validation.Valid; + + +/** + * + * @Description 群控管理-影刀定时器-日志模块 + * @Date 2022-07-20 + * @Author rch + */ +@Validated +@RequestMapping("/api/quartzLog") +@RestController +@RequiredArgsConstructor +@Api(tags = "业务:影刀定时任务日志管理") +public class QuartzLogController { + + @Resource + private SysQuartzLogService sysQuartzLogService; + /** + * 分页查询影刀日志信息 + */ + @ApiOperation("分页查询影刀日志信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询影刀任务信息") + @AnonymousAccess + @PostMapping("/list") + public Dto getLogsList(@Valid @RequestBody SysQuartzLogListDTO dto) { + PageUtils pageUtilsResult= sysQuartzLogService.searchPageList(dto.getiPage(), dto.getWrapper()); + return Dto.returnResult(pageUtilsResult); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/SdsController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/SdsController.java new file mode 100644 index 0000000..83943bf --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/SdsController.java @@ -0,0 +1,320 @@ +package me.zhengjie.modules.group.controller.base; + + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.Log; +import me.zhengjie.dto.Dto; +import me.zhengjie.service.vo.CtApplyListVO; +import me.zhengjie.utils.HttpClientUtil; +import me.zhengjie.utils.MD5Util; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +/** + * Author: rch + * Data: 2022-11-21 + * Description SDS验签 + */ +@Validated +@RequestMapping("/api/sds") +@RestController +@Api(tags = "业务:SDS验签") +public class SdsController { + + String sdsUrlPro = "https://merchantapi.sdspod.com"; + String sdsUrlTest = "https://merchantapitest.sdspod.com"; + String appId = "LPE3NKxile1dr0TGW5hOyFzfc8S4tBUR"; + String appsecret = "DNZlt9UYOAcwCx3evHEM7nr8kuz1XRGsWjJyQpKFq5SdPf0oabBm46hVgiT2LIHViRkIFojPUV7O4FM5SQZsivJ734X7YgPBuYgyH85OUoGzbzj9Wa1Smd1AYC4GyUHA"; + + // 上传图片接口 +// @ApiOperation("上传图片接口") +// @Log("上传图片接口") +// @PostMapping("/url") +// @AnonymousAccess +// public Dto url(@Valid @RequestBody ImageUrlDTO dto){ +// +// return Dto.returnErrorResult("true"); +// } + + @ApiOperation("获取可设计产品的信息") + @Log("获取可设计产品的信息") + @GetMapping("/products") + @AnonymousAccess + public Dto products(@RequestParam(value = "page") Integer page, + @RequestParam(value = "size") Integer size){ + + // sdsUrlTest + Long millisTime = System.currentTimeMillis(); + String url = "/gateway/products/design_infos"; + Map map = new HashMap<>(); + map.put("page", page); + map.put("size", size); + map.put("_timestamp", millisTime); + + String sign = getSign(map); + System.out.println("生成sign的url:" + sign); + String md5Sign = MD5Util.md5(sign); + System.out.println("生成的sign:" + md5Sign); + map.clear(); + map.put("_appid", appId); + map.put("_timestamp", millisTime); + map.put("_sign", md5Sign); + map.put("page", page); + map.put("size", size); + + String realStrUrl = sdsUrlPro + url; + String returnStr = HttpClientUtil.getHttp(realStrUrl, map); + System.out.println("获取可设计产品的信息:" + returnStr); + return Dto.returnErrorResult(returnStr); + } + + @ApiOperation("获取产品详情") + @Log("获取产品详情") + @GetMapping("/productsDetail") + @AnonymousAccess + public Dto products(@RequestParam Integer id){ + + // sdsUrlTest + Long millisTime = System.currentTimeMillis(); + String url = "/gateway/products/" + id; + Map map = new HashMap<>(); + map.put("_timestamp", millisTime); + + String sign = getSign(map); + System.out.println("生成sign的url:" + sign); + String md5Sign = MD5Util.md5(sign); + System.out.println("生成的sign:" + md5Sign); + map.clear(); + map.put("_sign", md5Sign); + map.put("_timestamp", millisTime); + map.put("_appid", appId); + + String realStrUrl = sdsUrlPro + url; + String returnStr = HttpClientUtil.getHttp(realStrUrl, map); + System.out.println("获取产品详情:" + returnStr); + return Dto.returnErrorResult(returnStr); + } + + + @ApiOperation("获取成品列表") + @Log("获取成品列表") + @GetMapping("/endproducts") + @AnonymousAccess + public Dto endproducts(@RequestParam(value = "page") Integer page, + @RequestParam(value = "size") Integer size, + @RequestParam(value = "userId", required = false) Long userId, + @RequestParam(value = "designProductType", required = false) String designProductType){ + + // sdsUrlTest + Long millisTime = System.currentTimeMillis(); + String url = "/gateway/endproducts"; + Map map = new HashMap<>(); + map.put("page", page); + map.put("size", size); + map.put("_timestamp", millisTime); +// map.put("userId", page); +// map.put("designProductType", "SINGLE"); + + String sign = getSign(map); + System.out.println("生成sign的url:" + sign); + String md5Sign = MD5Util.md5(sign); + System.out.println("生成的sign:" + md5Sign); + map.clear(); + map.put("_appid", appId); + map.put("_timestamp", millisTime); + map.put("_sign", md5Sign); + map.put("page", page); + map.put("size", size); +// map.put("designProductType", "SINGLE"); + + String realStrUrl = sdsUrlPro + url; + String returnStr = HttpClientUtil.getHttp(realStrUrl, map); + System.out.println("获取成品列表响应:" + returnStr); + return Dto.returnErrorResult(returnStr); + } + + + // url getUrlHttp + @ApiOperation("获取成品列表Url") + @Log("获取成品列表Url") + @GetMapping("/endproductsUrl") + @AnonymousAccess + public Dto endproductsUrl(@RequestParam(value = "page") Integer page, + @RequestParam(value = "size") Integer size, + @RequestParam(value = "userId", required = false) Long userId, + @RequestParam(value = "designProductType", required = false) String designProductType){ + + // sdsUrlTest + Long millisTime = System.currentTimeMillis(); + String url = "/gateway/endproducts"; + Map map = new HashMap<>(); + map.put("page", page); + map.put("size", size); + map.put("_timestamp", millisTime); +// map.put("userId", page); +// map.put("designProductType", "SINGLE"); + + String sign = getSign(map); + System.out.println("生成sign的url:" + sign); + String md5Sign = MD5Util.md5(sign); + System.out.println("生成的sign:" + md5Sign); + map.clear(); + + map.put("_appid", appId); + map.put("_timestamp", millisTime); + map.put("_sign", md5Sign); + map.put("page", page); + map.put("size", size); +// map.put("designProductType", "SINGLE"); + + String realStrUrl = sdsUrlPro + url + "?page=" + page + "&size=" + size + "&_appid=" + appId + "&_sign=" + md5Sign + "&_timestamp=" + millisTime; + System.out.println("realStrUrl:" + realStrUrl); + String returnStr = HttpClientUtil.getUrlHttp(realStrUrl); + System.out.println("获取成品列表响应:" + returnStr); + return Dto.returnErrorResult(returnStr); + } + + @ApiOperation("根据成品ID获取成品信息") + @Log("根据成品ID获取成品信息") + @GetMapping("/endproductsById") + @AnonymousAccess + public Dto endproductsById(@RequestParam(value = "id") String id){ + // sdsUrlTest + Long millisTime = System.currentTimeMillis(); + String url = "/gateway/endproducts/" + id; + Map map = new HashMap<>(); + map.put("_timestamp", millisTime); + + String sign = getSign(map); + System.out.println("生成sign的url:" + sign); + String md5Sign = MD5Util.md5(sign); + System.out.println("生成的sign:" + md5Sign); + map.clear(); + map.put("_sign", md5Sign); + map.put("_timestamp", millisTime); + map.put("_appid", appId); + + String realStrUrl = sdsUrlPro + url; + String returnStr = HttpClientUtil.getHttp(realStrUrl, map); + System.out.println("根据成品ID获取成品信息:" + returnStr); + return Dto.returnErrorResult(returnStr); + } + + + @ApiOperation("根据成品ID获取成品详细信息包含产品详细信息") + @Log("根据成品ID获取成品详细信息包含产品详细信息") + @GetMapping("/endproductsDetailById") + @AnonymousAccess + public Dto endproductsDetailById(@RequestParam(value = "id") String id){ + // sdsUrlTest + Long millisTime = System.currentTimeMillis(); + String url = "/gateway/endproducts/" + id + "/huajuDetail"; + Map map = new HashMap<>(); + map.put("_timestamp", millisTime); + + String sign = getSign(map); + System.out.println("生成sign的url:" + sign); + String md5Sign = MD5Util.md5(sign); + System.out.println("生成的sign:" + md5Sign); + map.clear(); + map.put("_sign", md5Sign); + map.put("_timestamp", millisTime); + map.put("_appid", appId); + + String realStrUrl = sdsUrlPro + url; + String returnStr = HttpClientUtil.getHttp(realStrUrl, map); + System.out.println("根据成品ID获取成品详细信息包含产品详细信息:" + returnStr); + return Dto.returnErrorResult(returnStr); + } + + + @ApiOperation("地址") + @Log("地址") + @GetMapping("/areas") + @AnonymousAccess + public Dto areas(@RequestParam(value = "area_code", required = false) Long areaCode){ + + // sdsUrlTest + Long millisTime = System.currentTimeMillis(); + String url = "/gateway/areas/" + areaCode + "/items"; + Map map = new HashMap<>(); +// map.put("area_code", areaCode); + map.put("_timestamp", millisTime); + String sign = getSign(map); + String md5Sign = MD5Util.md5(sign); + map.clear(); + map.put("_sign", md5Sign); + map.put("_timestamp", millisTime); + map.put("_appid", appId); + + String realStrUrl = sdsUrlPro + url; + String returnStr = HttpClientUtil.getHttp(realStrUrl, map); + System.out.println("地址:" + returnStr); + return Dto.returnErrorResult(returnStr); + } + + + @ApiOperation("素材") + @Log("素材") + @GetMapping("/gateway/materials") + @AnonymousAccess + public Dto materials(@RequestParam(value = "page") Integer page, + @RequestParam(value = "size") Integer size, + @RequestParam(value = "userId", required = false) Long userId){ + + // sdsUrlTest + Long millisTime = System.currentTimeMillis(); + String url = "/gateway/materials"; + Map map = new HashMap<>(); + map.put("page", page); + map.put("size", size); + map.put("_timestamp", millisTime); +// map.put("userId", page); +// map.put("designProductType", "SINGLE"); + + String sign = getSign(map); + System.out.println("生成sign的url:" + sign); + String md5Sign = MD5Util.md5(sign); + System.out.println("生成的sign:" + md5Sign); + map.clear(); + + map.put("_appid", appId); + map.put("_timestamp", millisTime); + map.put("_sign", md5Sign); + map.put("page", page); + map.put("size", size); +// map.put("designProductType", "SINGLE"); + + String realStrUrl = sdsUrlPro + url + "?page=" + page + "&size=" + size + "&_appid=" + appId + "&_sign=" + md5Sign + "&_timestamp=" + millisTime; + System.out.println("realStrUrl:" + realStrUrl); + String returnStr = HttpClientUtil.getUrlHttp(realStrUrl); + System.out.println("获取成品列表响应:" + returnStr); + return Dto.returnErrorResult(returnStr); + } + + // Get验签 + public String getSign(Map map) { + + map.put("_appid", appId); + map.put("_appsecret", appsecret); + + + TreeMap params = new TreeMap(); + params.putAll(map); + + StringBuilder strBuilder = new StringBuilder(); + for (String key : params.keySet()) { + strBuilder.append(key).append("=").append(params.get(key)).append("&"); + } + strBuilder.deleteCharAt(strBuilder.length() - 1); + System.out.println(strBuilder); + return strBuilder.toString(); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/SysQuartzJobController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/SysQuartzJobController.java new file mode 100644 index 0000000..7e5a4d3 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/SysQuartzJobController.java @@ -0,0 +1,206 @@ +package me.zhengjie.modules.group.controller.base; + + +import cn.hutool.core.lang.Snowflake; +import cn.hutool.core.util.ObjectUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.FormSubmission; +import me.zhengjie.annotation.Log; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.CtApply; +import me.zhengjie.entity.SysQuartzJob; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.modules.group.dto.IdDTO; +import me.zhengjie.modules.group.dto.SysQuartzJobAddDTO; +import me.zhengjie.modules.group.dto.SysQuartzJobListDTO; +import me.zhengjie.modules.group.dto.SysQuartzJobUpdateDTO; +import me.zhengjie.modules.quartz.service.SysQuartzJobService; +import me.zhengjie.service.CtApplyService; +import me.zhengjie.utils.StringUtils; +import me.zhengjie.utils.YdParamsCheck; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.validation.Valid; + +/** + * @Description 群控管理-影刀定时任务 + * @Date 2022/7/21 + * @Author zhw + */ +@Validated +@RequestMapping("/api/quartzJob") +@RestController +@Api(tags = "业务:影刀定时任务管理") +public class SysQuartzJobController { + @Resource + private SysQuartzJobService sysQuartzJobService; + @Resource + private CtApplyService ctApplyService; + @Resource + private Snowflake snowflake; + + + /** + * 分页查询影刀任务信息 + */ + @ApiOperation("分页查询影刀任务信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("分页查询影刀任务信息") + @AnonymousAccess + @PostMapping("/list") + public Dto getQuartzJobList(@Valid @RequestBody SysQuartzJobListDTO dto) { + return Dto.returnResult(sysQuartzJobService.searchPageList(dto.getiPage(), dto.getWrapper())); + } + + /** + * 新增影刀任务信息 + */ + @ApiOperation("新增影刀任务信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3401, message = "影刀应用信息异常, 请检查后重试!") + }) + @Log("新增影刀任务信息") + @AnonymousAccess + @PostMapping("/add") + @FormSubmission + @Transactional(rollbackFor = Exception.class) + public Dto addQuartzJob(@Valid @RequestBody SysQuartzJobAddDTO dto) { + + // TODO 应用已后台添加的枚举 TaskInfoEnum 为准 根据 taskName 区分应用 逻辑 匹配params + CtApply ctApply = ctApplyService.getById(dto.getApplyId()); + if (ObjectUtil.isEmpty(ctApply)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_TASK); + } + + String taskName = ctApply.getTaskName(); + String params = dto.getParams(); + Long taskNum = snowflake.nextId(); + dto.setTaskNum(taskNum); + // TODO 客户端处理 走 param模式还是 回显模式 这里先设置未null + if (!YdParamsCheck.paramIsJson(params)) { + // 测试的第一个应用 刷单 拼装params + String assemblyParams = sysQuartzJobService.assemblyParamAccordingToItem(params, taskName, taskNum); + if (StringUtils.isEmpty(assemblyParams)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_TASK); + } else { + dto.setParams(assemblyParams); + } + } + + return sysQuartzJobService.addQuartzJob(dto); + } + + /** + * 根据ID删除影刀任务信息 + */ + @ApiOperation("根据ID删除影刀任务信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据ID删除影刀任务信息") + @PostMapping("/delete") + public Dto deleteQuartzJob(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(sysQuartzJobService.deleteQuartzJobById(idDTO.getId())); + } + + /** + * 编辑影刀任务信息 + */ + @ApiOperation("编辑影刀任务信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3401, message = "影刀应用信息异常, 请检查后重试!") + }) + @Log("编辑影刀任务信息") + @PostMapping("/edit") + @FormSubmission + public Dto updateQuartzJob(@Valid @RequestBody SysQuartzJobUpdateDTO dto) { + CtApply ctApply = ctApplyService.getById(dto.getApplyId()); + if (ObjectUtil.isEmpty(ctApply)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_TASK); + } + String taskName = ctApply.getTaskName(); + String params = dto.getParams(); + // TODO 客户端处理 走 param模式还是 回显模式 这里先设置未null + if (!YdParamsCheck.paramIsJson(params)) { + // TODO 先这样吧,先不回头去调整了。先能弄不考虑其他 + SysQuartzJob sysQuartzJob = sysQuartzJobService.getById(dto.getJobId()); + // 测试的第一个应用 刷单 拼装params + String assemblyParams = sysQuartzJobService.assemblyParamAccordingToItem(params, taskName, sysQuartzJob.getTaskNum()); + if (StringUtils.isEmpty(assemblyParams)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_TASK); + } else { + dto.setParams(assemblyParams); + } + } + return sysQuartzJobService.updateQuartzJobById(dto); + } + + /** + * 根据ID查询影刀任务信息 + */ + @ApiOperation("根据ID查询影刀任务信息") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据ID查询影刀任务信息") + @PostMapping("/getById") + public Dto getQuartzJobById(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(sysQuartzJobService.getById(idDTO.getId())); + } + + /** + * 根据ID修改任务状态 + * @param idDTO + * @return + */ + @ApiOperation("根据ID修改任务状态") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("根据ID修改任务状态") + @PostMapping("/modifyStatus") + public Dto modifyJobStatus(@Valid @RequestBody IdDTO idDTO) { + return Dto.returnResult(sysQuartzJobService.modifyJobStatus(idDTO.getId())); + } + + /** + * 执行影刀任务 + * + * + * @param idDTO + * @return Dto + */ + @ApiOperation("执行影刀任务") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!") + }) + @Log("执行定时任务") + @PostMapping("/exec") + public Dto execution(@Valid @RequestBody IdDTO idDTO) { + Boolean one = true; + one = !one; + return Dto.returnResult(sysQuartzJobService.executionById(idDTO.getId())); + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/YdCallBackController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/YdCallBackController.java new file mode 100644 index 0000000..d3c4589 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/base/YdCallBackController.java @@ -0,0 +1,122 @@ +package me.zhengjie.modules.group.controller.base; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.Log; +import me.zhengjie.config.YdApiProperties; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.CtRebot; +import me.zhengjie.entity.ReturnObje; +import me.zhengjie.entity.YdSign; +import me.zhengjie.enums.YesOrNoEnum; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.service.CtRebotService; +import me.zhengjie.utils.YdSignUtil; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.Map; + +/** + * @Description + * @Date 2022/7/23 + * @Author rch + */ +@Slf4j +@Validated +@RequestMapping("/api/yd") +@RestController +@Api(tags = "业务:影刀回调管理Demo") +public class YdCallBackController { + + @Resource + private CtRebotService ctRebotService; + /** + * 影刀回调Demo + */ + @ApiOperation("影刀回调Demo") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3700, message = "影刀回调参数空值异常!"), + @ApiResponse(code = 3701, message = "影刀回调鉴权异常!") + }) + @Log(value = "影刀回调") + @PostMapping("/callback") + @AnonymousAccess + public Dto callback(@Valid @RequestBody String data, HttpServletRequest httpServletRequest){ + log.info("=======影刀回调=======callback"); + String requestUrl = httpServletRequest.getRequestURI(); + Map map = httpServletRequest.getParameterMap(); + if (ObjectUtil.isEmpty(map.get("sign"))) { + return Dto.getInstance(ErrorCodeEnum.ERROR_PARAM_NULL); + } + + String getSign = map.get("sign")[0]; + JSONObject jsonObject = JSONUtil.parseObj(data); + String accessKeyId = YdApiProperties.ACCESS_KEY_ID; + String accessKeySecret = YdApiProperties.ACCESS_KEY_SECRET; + if (ObjectUtil.isEmpty(getSign) + || ObjectUtil.isEmpty(jsonObject) + || ObjectUtil.isEmpty(accessKeyId) + || ObjectUtil.isEmpty(accessKeySecret)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_PARAM_NULL); + } + + // 根据task枚举获取 应用信息 取出 accessKey 和 accessKeySecret 用于鉴权 + + + // 鉴权 + YdSign ydSign = new YdSign(); + ydSign.setTimestamp(Long.valueOf(map.get("timestamp")[0])); + ydSign.setAccessKeyId(accessKeyId); + ydSign.setAccessKeySecret(accessKeySecret); + ydSign.setBodyMd5(map.get("bodyMd5")[0]); + + log.info("-------map:{}" , JSONUtil.toJsonStr(map)); + log.info("====ydSign====={}", JSONUtil.toJsonStr(ydSign)); + String sign = YdSignUtil.getSign(ydSign); + log.info("====sign:{} ---getSign:{}", sign, getSign); + if (ObjectUtil.isEmpty(sign) || !getSign.equals(sign)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_CALLBACK_SIGN_NULL); + } + + System.out.println("===================data:" + data); + + + // TODO 拿到返回信息 根据回调知道是那个应用的业务场景 这里算是刷单系统的 + // 1.得到结果 根据结果修改 刷单信息状态 以及响应信息 + + + // TODO 获取设备id 然后修改设备状态是未占用 + ReturnObje returnObje = JSONUtil.toBean(data, ReturnObje.class); + String rebotClientName = returnObje.getRobotClientName(); + CtRebot ctRebot = ctRebotService.getByAccountNameLock(rebotClientName); + if (ObjectUtil.isEmpty(ctRebot) || !YesOrNoEnum.YES.eqValue(ctRebot.getStatus())) { + // 有问题 不执行 + System.out.println("===========设备有问题==========="); + return Dto.returnResult(true); + } else { + // 修改机器人状态 不管是什么状态,执行完成之后在我们平台就是修改为 待占用即可 + CtRebot updateCtRebot = new CtRebot(); + updateCtRebot.setId(ctRebot.getId()); + updateCtRebot.setStatus(YesOrNoEnum.NO.value()); + Boolean resultBoolean = ctRebotService.updateById(updateCtRebot); + return Dto.returnResult(resultBoolean); + } + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/BossTaskCallBackController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/BossTaskCallBackController.java new file mode 100644 index 0000000..ce0894e --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/BossTaskCallBackController.java @@ -0,0 +1,84 @@ +package me.zhengjie.modules.group.controller.callbcak; + +import cn.hutool.json.JSONUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.Log; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.CtApply; +import me.zhengjie.entity.ReturnObje; +import me.zhengjie.entity.quartz.JobQueryByUuidReturn; +import me.zhengjie.enums.TaskInfoEnum; +import me.zhengjie.service.CtApplyService; +import me.zhengjie.service.YdQuartzService; +import me.zhengjie.utils.YdCallBackUtil; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; + +/** + * @Description + * @Date 2022/7/23 + * @Author rch + */ +@Slf4j +@Validated +@RequestMapping("/api/bossTask") +@RestController +@Api(tags = "回调:Boss-职位查询采集-影刀回调") +public class BossTaskCallBackController { + + @Resource + private CtApplyService ctApplyService; + @Resource + private YdQuartzService ydQuartzService; + /** + * Boss-职位查询采集-影刀回调 + */ + @ApiOperation("Boss-职位查询采集-影刀回调") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3700, message = "影刀回调参数空值异常!"), + @ApiResponse(code = 3701, message = "影刀回调鉴权异常!") + }) + @Log(value = "Boss-职位查询采集-影刀回调") + @PostMapping("/callback") + @AnonymousAccess + public Dto callback(@Valid @RequestBody String data, HttpServletRequest httpServletRequest){ + // 根据task枚举获取 应用信息 取出 accessKey 和 accessKeySecret 用于鉴权 + YdCallBackUtil ydCallBackUtil = new YdCallBackUtil(); + CtApply ctApply = ctApplyService.getApplyByTaskAndMethod(TaskInfoEnum.BOSS_TASK.getTaskName(), TaskInfoEnum.BOSS_TASK.getMethodName()); + Dto dto = ydCallBackUtil.callback(httpServletRequest, ctApply, data); + if (!dto.success(dto)) { + return dto; + } + + // 执行自己的业务逻辑 + log.info("============bossTask 回调鉴权完成 开始执行对应的定时业务逻辑================begin="); + // 获取自己想要的数据 + ReturnObje returnObje = JSONUtil.toBean(data, ReturnObje.class); + log.info("====returnObje====:{}", JSONUtil.toJsonStr(returnObje)); + // 获取应用名称 获取机器人名称 + // 执行自己的业务逻辑 + log.info("============刷单回调鉴权完成 开始执行对应的定时业务逻辑================begin="); + log.info("回调======data:" + data); + // 获取自己想要的数据 + JobQueryByUuidReturn jobQueryByUuidReturn = ydQuartzService.queryJobUuid(returnObje.getJobUuid(), ctApply.getAccessKeyId(), ctApply.getAccessKeySecret()); + log.info("====jobQueryByUuidReturn====:{}", JSONUtil.toJsonStr(jobQueryByUuidReturn)); + + log.info("============bossTask 回调鉴权完成 开始执行对应的定时业务逻辑================end==="); + return dto; + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/ClickFarmingCallBackController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/ClickFarmingCallBackController.java new file mode 100644 index 0000000..3887c5d --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/ClickFarmingCallBackController.java @@ -0,0 +1,432 @@ +package me.zhengjie.modules.group.controller.callbcak; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.lang.Snowflake; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.Log; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.*; +import me.zhengjie.entity.quartz.Boss; +import me.zhengjie.entity.quartz.JobQueryByUuidReturn; +import me.zhengjie.entity.quartz.Param; +import me.zhengjie.enums.*; +import me.zhengjie.modules.quartz.service.SysQuartzJobService; +import me.zhengjie.service.*; +import me.zhengjie.service.vo.CtBuyerDetailVO; +import me.zhengjie.utils.CronUtils; +import me.zhengjie.utils.RedisUtils; +import me.zhengjie.utils.YdCallBackUtil; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.stream.Collectors; + +/** + * @Description + * 刷单定时任务回调逻辑 + * 回调需要鉴权,鉴权是根据 accesskey accessKeySrect + * 我们应用确认之后 accesskey 和 Srect是确定的 + * + * @Date 2022-8-23 + * @Author rch + */ +@Slf4j +@Validated +@RequestMapping("/api/clickFarming") +@RestController +@Api(tags = "回调:速卖通刷单-影刀回调") +public class ClickFarmingCallBackController { + + @Resource + private CtApplyService ctApplyService; + @Resource + private YdQuartzService ydQuartzService; + @Resource + private CtClickFarmingService ctClickFarmingService; + @Resource + private CtClickOrderService ctClickOrderService; + @Resource + private RedisUtils redisUtils; + @Resource + private CtBuyerService ctBuyerService; + @Resource + private SysQuartzJobService sysQuartzJobService; + @Resource + private Snowflake snowflake; + @Resource + private SettingSiteService settingSiteService; + + private final String STAET_MODULAR = "】任务失败,在【"; + private final String END_MODULAR = "】中第"; + private final String END_LINE_NUMBER = "行:出错"; + private final Integer START_TASK_TIME = 20; + private final String RE_EXECTE_KEY = "reExecuteKey"; + /** + * 速卖通刷单-影刀回调 + */ + @ApiOperation("速卖通刷单-影刀回调") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3700, message = "影刀回调参数空值异常!"), + @ApiResponse(code = 3701, message = "影刀回调鉴权异常!") + }) + @Log(value = "速卖通刷单-影刀回调") + @PostMapping("/callback") + @AnonymousAccess + @Transactional(rollbackFor = Exception.class) + public Dto callback(@Valid @RequestBody String data, HttpServletRequest httpServletRequest){ + + // 根据task枚举获取 应用信息 取出 accessKey 和 accessKeySecret 用于鉴权 + YdCallBackUtil ydCallBackUtil = new YdCallBackUtil(); + CtApply ctApply = ctApplyService.getApplyByTaskAndMethod(TaskInfoEnum.CLICK_FARMING.getTaskName(), TaskInfoEnum.CLICK_FARMING.getMethodName()); + Dto dto = ydCallBackUtil.callback(httpServletRequest, ctApply, data); + if (!dto.success(dto)) { + return dto; + } + + // 执行自己的业务逻辑 + log.info("============刷单回调鉴权完成 开始执行对应的定时业务逻辑================begin="); + log.info("回调======data:" + data); + // 获取自己想要的数据 + ReturnObje returnObje = JSONUtil.toBean(data, ReturnObje.class); + // job ID + String jobUuid = returnObje.getJobUuid(); + + // TODO 回调会重试 这里注意保证幂等 + // TODO 所以需要对接方在业务层面保障幂等(可以根据jobUuid或者taskUuid进行幂等保障,视startJob时是指定应用和机器人模式还是指定任务模式) + String keyJobUuid = PublicConstant.getJobUuidKeyPrefix(jobUuid); + if (!redisUtils.setIfAbsent(keyJobUuid, DateUtil.now())) { + log.info("-刷单回调接口-幂等性:keyJobUuid:" + keyJobUuid); + return Dto.returnResult(true); + } + + log.info("====returnObje====:{}", JSONUtil.toJsonStr(returnObje)); + JobQueryByUuidReturn jobQueryByUuidReturn = ydQuartzService.queryJobUuid(returnObje.getJobUuid(), ctApply.getAccessKeyId(), ctApply.getAccessKeySecret()); + log.info("====jobQueryByUuidReturn====:{}", JSONUtil.toJsonStr(jobQueryByUuidReturn)); + List inputsList = jobQueryByUuidReturn.getData().getRobotParams().getInputs(); + // 获取id + String id = null; + String buyerName = null; + String taskNum = null; + for (ResultObj resultObj:inputsList) { + if ("id".equals(resultObj.getName())) { + id = resultObj.getValue(); + } + + if ("account".equals(resultObj.getName())) { + buyerName = resultObj.getValue(); + } + + if ("taskNum".equals(resultObj.getName())) { + taskNum = resultObj.getValue(); + } + } + + Integer status = ClickFarmingStatusEnum.EXECUTION_FAILE.value(); + if ("finish".equals(jobQueryByUuidReturn.getData().getStatus())) { + status = ClickFarmingStatusEnum.EXECUTION_SUCCESS.value(); + } + + // 执行失败 + Boolean resultBoolean = false; + if (ObjectUtil.isNotEmpty(id)) { + CtClickFarming ctClickFarming = new CtClickFarming(); + ctClickFarming.setId(Long.valueOf(id)); + + // 获取买家信息并修改买家信息 + CtBuyer ctBuyer = ctBuyerService.getBuyerOccupyStatusLock(buyerName); + if (ObjectUtil.isNotEmpty(ctBuyer) && BuyerOccupyStatusEnum.OCCUPIED.value().equals(ctBuyer.getOccupyStatus())) { + ctBuyer.setOccupyStatus(BuyerOccupyStatusEnum.UN_OCCUPIED.value()); + resultBoolean = ctBuyerService.updateById(ctBuyer); + } + + // TODO 需要更新的字段 从这里获取影刀返回的 然后接着设置到 对应的 基础信息里 + List outputsList = jobQueryByUuidReturn.getData().getRobotParams().getOutputs(); + if (resultBoolean && ObjectUtil.isNotEmpty(outputsList)) { + Map resultObjMap = outputsList.stream().collect(Collectors.toMap(ResultObj::getName, ResultObj::getValue)); + CtClickOrder ctClickOrder = BeanUtil.mapToBean(resultObjMap, CtClickOrder.class, false); + if (ObjectUtil.isNotEmpty(ctClickOrder)) { + if (ObjectUtil.isNotEmpty(ctClickOrder.getPaymentResults()) && "Awaiting payment".equals(ctClickOrder.getPaymentResults())) { + status = ClickFarmingStatusEnum.AWAITING_PAYMENT.value(); + } + // 设置订单 公司 平台信息 + ctClickOrder.setCompanyId(ctBuyer.getCompanyId()); + ctClickOrder.setType(OrderTypeEnum.CLICK_FARMING.value()); + if (ctClickOrderService.save(ctClickOrder)) { + ctClickFarming.setCtClickOrderId(ctClickOrder.getId()); + } + } + } else { + // 解析json 返回错误类型 + status = analysisReturnJson(jobQueryByUuidReturn.getData().getRemark()); + } + + ctClickFarming.setStatus(status); + if (ClickFarmingStatusEnum.EXECUTION_FAILE.value().equals(status) || ClickFarmingStatusEnum.PAY_OK_ERROR.value().equals(status) || ClickFarmingStatusEnum.AWAITING_PAYMENT.value().equals(status)) { + ctClickFarming.setResponse(jobQueryByUuidReturn.getData().getRemark()); + }else { + ctClickFarming.setResponse(jobQueryByUuidReturn.getData().getStatusName()); + } + resultBoolean = ctClickFarmingService.updateById(ctClickFarming); + // TODO 判断状态 如果是执行失败 (未下单成功 未支付的则直接重新创建任务重新执行-(换个买家)) + /** + * 1.根据买家规则返回买家信息 + * 2.用新买家信息 创建新的定时任务 + */ + // 查询刷单信息 默认不执行 只有设置1才执行 + String reExecuteValue = settingSiteService.getValue(RE_EXECTE_KEY); + if (ObjectUtil.isNotEmpty(reExecuteValue) && "1".equals(reExecuteValue)) { + CtClickFarming ctClickFarmingOld = ctClickFarmingService.getById(id); + if (ClickFarmingStatusEnum.EXECUTION_FAILE.value().equals(status)) { + SysQuartzJob sysQuartzJob = sysQuartzJobService.getByTaskNum(taskNum); + if (ObjectUtil.isEmpty(sysQuartzJob)) { + return Dto.returnResult(false); + } + resultBoolean = reExecuteTask(sysQuartzJob, ctClickFarmingOld); + } + } + } + + log.info("============刷单回调鉴权完成 开始执行对应的定时业务逻辑================end==="); + return Dto.returnResult(resultBoolean); + } + + /** + * 执行失败-重新创建定时任务 + * @param sysQuartzJob + * @return + */ + private Boolean reExecuteTask(SysQuartzJob sysQuartzJob, CtClickFarming ctClickFarming) { + // TODO 根据规则 修改 param 参数信息 以及 + log.info("刷单任务-执行失败-重新创建定时任务--sysQuartzJob:{} --ctClickFarming:{}", JSONUtil.toJsonStr(sysQuartzJob), JSONUtil.toJsonStr(ctClickFarming)); + // 创建后启用状态 并且 失败不暂停(失败后要暂停的) + sysQuartzJob.setIsPause(TaskIsPauseEnum.NOT_PAUSE.value()); + sysQuartzJob.setPauseAfterFailure(TaskIsPauseEnum.IS_PAUSE.value()); + // 设置执行时间 + String cronStr = CronUtils.onlyOnce(DateUtil.formatDateTime(DateUtil.offsetSecond(DateUtil.date(), START_TASK_TIME))); + sysQuartzJob.setCronExpression(cronStr); + // 新的定时任务taskNum + Long taskNum = snowflake.nextId(); + sysQuartzJob.setJobName(jobNameNew(sysQuartzJob.getJobName(), sysQuartzJob.getTaskNum().toString())); + // 买家信息 + String paramsStr = sysQuartzJob.getParams(); + Boss bossObj = JSONUtil.toBean(paramsStr, Boss.class); + log.info("bossObj--before:" + JSONUtil.toJsonStr(bossObj)); + List paramList = bossObj.getParams(); + Param paramAccount = paramList.stream().filter(r->"account".equals(r.getName())).findFirst().get(); + Param paramCountry = paramList.stream().filter(r->"country".equals(r.getName())).findFirst().get(); + // 替换新的买家信息 + CtBuyerDetailVO ctBuyerDetailVO = getRuleCtBuyer(paramAccount.getValue(), paramCountry.getValue(), ctClickFarming); + if (ObjectUtil.isEmpty(ctBuyerDetailVO)) { + log.info("买家信息全部执行完成,没有可选择的买家信息!-任务不在重试"); + return false; + } + for (Param paramObj:paramList) { + if (("country").equals(paramObj.getName())) { + paramObj.setValue(ctBuyerDetailVO.getCountry()); + } + if (("account").equals(paramObj.getName())) { + paramObj.setValue(ctBuyerDetailVO.getAccount()); + } + if (("pwd").equals(paramObj.getName())) { + paramObj.setValue(ctBuyerDetailVO.getPwd()); + } + if (("vpnShare").equals(paramObj.getName())) { + paramObj.setValue(ctBuyerDetailVO.getVpn()); + } + // 信用卡 + if (("cardName").equals(paramObj.getName())) { + paramObj.setValue(ctBuyerDetailVO.getHolderSurname() + " " + ctBuyerDetailVO.getHolderName()); + } + if (("cardNumber").equals(paramObj.getName())) { + paramObj.setValue(ctBuyerDetailVO.getNumber()); + } + if (("cardPwd").equals(paramObj.getName())) { + paramObj.setValue(ctBuyerDetailVO.getCardPwd()); + } + if (("taskNum").equals(paramObj.getName())) { + paramObj.setValue(taskNum.toString()); + } + } + + log.info("bossObj--after:" + JSONUtil.toJsonStr(bossObj)); + sysQuartzJob.setParams(JSONUtil.toJsonStr(bossObj)); + sysQuartzJob.setTaskNum(taskNum); + + sysQuartzJobService.reAddQuartzJob(sysQuartzJob); + + return true; + } + + /** + * 返回新的jobName名字 + * 原则上传入的 jobName 和 taskNum 是同一个QuartzJob的。 + * 这个返回的 作为子集的 job_name = 父级原本的jobName + 父级的taskNum + * 为后续 排查使用 (最好是新设置一个字段,这里先这样) + * 说明: 父级的意思说的是 上级, 比如A任务 回调失败,换个买家 新创建任务B A就说是B的父级 + * @param jobName + * @param taskNum + * @return + */ + public String jobNameNew(String jobName, String taskNum) { + if (jobName.contains("-")) { + jobName = jobName.substring(0,jobName.lastIndexOf("-")); + } + + return jobName + "-" + taskNum; + } + + + /** + * 根据规则获取新的买家信息 + * @param buyerAccount + * @return + */ + public CtBuyerDetailVO getRuleCtBuyer(String buyerAccount, String country, CtClickFarming ctClickFarming) { + if (ObjectUtil.isEmpty(buyerAccount) + || ObjectUtil.isEmpty(country) + || ObjectUtil.isEmpty(ctClickFarming) + || ObjectUtil.isEmpty(ctClickFarming.getShopName()) + || ObjectUtil.isEmpty(ctClickFarming.getId())) { + return null; + } + // 获取所有成功的刷单信息买家 然后统计每个成功的个数并返回 同时剔除传过来的参数信息 + // TODO 这里不能无限制的取, 通过redis 根据 刷单id 设置取过的买家信息,取过的不再取了 + List ctBuyerClickSuccessList = ctClickFarmingService.ruleGetCtBuyer(buyerAccount, country, ctClickFarming.getShopName()); + String clickFarmingExecBuyerIdPrefix = PublicConstant.getClickFarmingExecBuyerIdPrefix(ctClickFarming.getId()); + Long setSize = redisUtils.sGetSetSize(clickFarmingExecBuyerIdPrefix); + Long buyerId = null; + if (setSize == 0) { + buyerId = ctBuyerClickSuccessList.get(new Random().nextInt(ctBuyerClickSuccessList.size())).getBuyerId(); + } else { + for (CtBuyerClickSuccess ctBuyerClickSuccess : ctBuyerClickSuccessList) { + buyerId = ctBuyerClickSuccess.getBuyerId(); + if (redisUtils.sHasKey(clickFarmingExecBuyerIdPrefix, buyerId.toString())) { + continue; + } + break; + } + System.out.println("没有取到合适的========================================"); + } + + if (ObjectUtil.isNotEmpty(buyerId)) { + redisUtils.sSet(clickFarmingExecBuyerIdPrefix, buyerId.toString()); + return ctBuyerService.getDetailById(buyerId); + } + return null; + } + + + + /** + * 解析json 区分错误类型 4.有订单id之前的异常 5.有订单未支付 6.支付成功异常 + * @param remark + * @return Integer + */ + private Integer analysisReturnJson(String remark) { + // 根据规则解析 + // "remark": "【0757f764-07b4-4d4d-a48d-e1e13b598a1f】任务失败,在【5-1清空银行卡】中第17行:出错:未找到元素, 元素名: 按钮_OK", + // "remark": "【9a92a414-e957-47f8-ada1-7296723769a9】任务失败,在【9-1优惠劵】中第7行:出错:未找到元素", + // "remark": "【60a92f00-f7cb-4321-aa0b-6f18814fb462】任务失败,在【3.切换国家】中第8行:出错:未找到元素", + // "remark": "【81f6c1ac-6493-40cf-83fd-867b1a39e3ca】任务失败,在【9-3添加银行卡】中第5行:出错:未找到元素, 元素名: SAVE CARD", + // "remark": "【e201a1b3-f0a1-42b9-8315-d6736eead5a4】任务失败,在【1-2清空浏览器数据】中第1行:出错:操作无法执行!请重启当前浏览器 或 重装当前浏览器插件后再次尝试。", +// 【923eea47-c056-47ef-bccf-930d8ef700da】任务失败,在【9-1.留言】中第2行:出错:未找到元素, 元素名: 留言板 +// private final String STAET_MODULAR = "】任务失败,在【"; +// private final String END_MODULAR = "】中第"; +// private final String END_LINE_NUMBER = "行:出错"; +// private final Integer START_TASK_TIME = 10; + /** + * 1.切换VPN + * 2.关闭弹窗 + * 3.清空浏览器 + * 4.切换国家 + * 5.登录 + * 6.清空购物车 + * 6-1.清空银行卡 + * 7.搜索商品 + * 7-1.随意浏览界面 + * 7-2.滚动鼠标浏览界面 + * 7-3.随机点击商品 + * 7-4.浏览随机商品 + * 7-5匹配商品信息 + * 8.商品下单 + * 8-1.滚动鼠标浏览商品 + * 8-2.查找规格 + * 8-3.查找颜色 + * 8-4.商品个数 + * 9.购物车-------------------------------有订单未支付:流程第19行点击Pay_now + * 9-1.留言 + * 9-2.添加银行卡 + * 9-3.选择银行卡有效时间 + * 9-4.选择优惠券 + * 10.回到首页----------------------回到首页:流程第11行点击首页 + * 11.获取订单信息 + * 12.退出账号 + */ + log.info(remark); + if (ObjectUtil.isEmpty(remark) + || !remark.contains("任务失败") + || !remark.contains("中第") + || !remark.contains("行:出错") + || remark.length() <= 12) { + return ClickFarmingStatusEnum.EXECUTION_FAILE.value(); + } + + String modular = remark.substring(remark.indexOf(STAET_MODULAR) + 8, remark.indexOf(END_MODULAR)); + String lineNumber = remark.substring(remark.indexOf(END_MODULAR) + 3, remark.indexOf(END_LINE_NUMBER)); + + // 子模块可以忽略 + Integer modularInteger = 0; + Integer lineNumberInteger = 0; + if (ObjectUtil.isNotEmpty(modular)) { + if (modular.contains(".") && !modular.contains("-") ) { + modularInteger = Integer.valueOf(modular.substring(0, modular.indexOf("."))); + } else if (modular.contains("-")) { + modularInteger = Integer.valueOf(modular.split("-")[0]); + } + } + if (ObjectUtil.isNotEmpty(lineNumber)) { + lineNumberInteger = Integer.valueOf(lineNumber); + } + + if (modularInteger < 9) { + return ClickFarmingStatusEnum.EXECUTION_FAILE.value(); + } else if(modularInteger == 9) { + if (lineNumberInteger <= 19) { + return ClickFarmingStatusEnum.EXECUTION_FAILE.value(); + } else { + return ClickFarmingStatusEnum.AWAITING_PAYMENT.value(); + } + } else if (modularInteger < 10){ + return ClickFarmingStatusEnum.AWAITING_PAYMENT.value(); + } else if(modularInteger == 10) { + if (lineNumberInteger <= 11) { + return ClickFarmingStatusEnum.AWAITING_PAYMENT.value(); + } else { + return ClickFarmingStatusEnum.PAY_OK_ERROR.value(); + } + } else { + return ClickFarmingStatusEnum.PAY_OK_ERROR.value(); + } + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/ClickFarmingSuppleMentCallBackController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/ClickFarmingSuppleMentCallBackController.java new file mode 100644 index 0000000..1250309 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/ClickFarmingSuppleMentCallBackController.java @@ -0,0 +1,234 @@ +package me.zhengjie.modules.group.controller.callbcak; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.Log; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.*; +import me.zhengjie.entity.quartz.JobQueryByUuidReturn; +import me.zhengjie.enums.BuyerOccupyStatusEnum; +import me.zhengjie.enums.ClickFarmingStatusEnum; +import me.zhengjie.enums.TaskInfoEnum; +import me.zhengjie.service.*; +import me.zhengjie.utils.RedisUtils; +import me.zhengjie.utils.YdCallBackUtil; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @Description + * 刷单补录定时任务回调逻辑 + * 回调需要鉴权,鉴权是根据 accesskey accessKeySrect + * 我们应用确认之后 accesskey 和 Srect是确定的 + * + * @Date 2022-8-23 + * @Author rch + */ +@Slf4j +@Validated +@RequestMapping("/api/clickFarmSupplyMent") +@RestController +@Api(tags = "回调:速卖通刷单补录-影刀回调") +public class ClickFarmingSuppleMentCallBackController { + + @Resource + private CtApplyService ctApplyService; + @Resource + private YdQuartzService ydQuartzService; + @Resource + private CtClickFarmingService ctClickFarmingService; + @Resource + private CtClickOrderService ctClickOrderService; + @Resource + private RedisUtils redisUtils; + @Resource + private CtBuyerService ctBuyerService; + + private final String STAET_MODULAR = "】任务失败,在【"; + private final String END_MODULAR = "】中第"; + private final String END_LINE_NUMBER = "行:出错"; + private final Integer START_TASK_TIME = 20; + + /** + * 速卖通刷单补录-回调 + */ + @ApiOperation("速卖通刷单补录-回调") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3700, message = "影刀回调参数空值异常!"), + @ApiResponse(code = 3701, message = "影刀回调鉴权异常!") + }) + @Log(value = "速卖通刷单补录-回调") + @PostMapping("/callback") + @AnonymousAccess + @Transactional(rollbackFor = Exception.class) + public Dto callback(@Valid @RequestBody String data, HttpServletRequest httpServletRequest){ + + // 根据task枚举获取 应用信息 取出 accessKey 和 accessKeySecret 用于鉴权 + YdCallBackUtil ydCallBackUtil = new YdCallBackUtil(); + CtApply ctApply = ctApplyService.getApplyByTaskAndMethod(TaskInfoEnum.CLICK_FARMING_SUPPLE_MENY.getTaskName(), TaskInfoEnum.CLICK_FARMING_SUPPLE_MENY.getMethodName()); + Dto dto = ydCallBackUtil.callback(httpServletRequest, ctApply, data); + if (!dto.success(dto)) { + return dto; + } + + // 执行自己的业务逻辑 + log.info("============刷单回调鉴权完成 开始执行对应的定时业务逻辑================begin="); + log.info("回调======data:" + data); + // 获取自己想要的数据 + ReturnObje returnObje = JSONUtil.toBean(data, ReturnObje.class); + // job ID + String jobUuid = returnObje.getJobUuid(); + + // TODO 回调会重试 这里注意保证幂等 + // TODO 所以需要对接方在业务层面保障幂等(可以根据jobUuid或者taskUuid进行幂等保障,视startJob时是指定应用和机器人模式还是指定任务模式) + String keyJobUuid = PublicConstant.getJobUuidKeyPrefix(jobUuid); + if (!redisUtils.setIfAbsent(keyJobUuid, DateUtil.now())) { + log.info("-刷单回调接口-幂等性:keyJobUuid:" + keyJobUuid); + return Dto.returnResult(true); + } + + log.info("====returnObje====:{}", JSONUtil.toJsonStr(returnObje)); + JobQueryByUuidReturn jobQueryByUuidReturn = ydQuartzService.queryJobUuid(returnObje.getJobUuid(), ctApply.getAccessKeyId(), ctApply.getAccessKeySecret()); + log.info("====jobQueryByUuidReturn====:{}", JSONUtil.toJsonStr(jobQueryByUuidReturn)); + List inputsList = jobQueryByUuidReturn.getData().getRobotParams().getInputs(); + // 获取id + String id = null; + String buyerName = null; + for (ResultObj resultObj:inputsList) { + if ("id".equals(resultObj.getName())) { + id = resultObj.getValue(); + } + + if ("account".equals(resultObj.getName())) { + buyerName = resultObj.getValue(); + } + } + +// Integer status = ClickFarmingStatusEnum.EXECUTION_FAILE.value(); + Integer status = ClickFarmingStatusEnum.AWAITING_PAYMENT.value(); + if ("finish".equals(jobQueryByUuidReturn.getData().getStatus())) { + status = ClickFarmingStatusEnum.EXECUTION_SUCCESS.value(); + } + + // 执行失败 + Boolean resultBoolean = false; + if (ObjectUtil.isNotEmpty(id)) { + CtClickFarming ctClickFarming = new CtClickFarming(); + ctClickFarming.setId(Long.valueOf(id)); + + // 获取买家信息并修改买家信息 + CtBuyer ctBuyer = ctBuyerService.getBuyerOccupyStatusLock(buyerName); + if (ObjectUtil.isNotEmpty(ctBuyer) && BuyerOccupyStatusEnum.OCCUPIED.value().equals(ctBuyer.getOccupyStatus())) { + ctBuyer.setOccupyStatus(BuyerOccupyStatusEnum.UN_OCCUPIED.value()); + resultBoolean = ctBuyerService.updateById(ctBuyer); + } + + // TODO 需要更新的字段 从这里获取影刀返回的 然后接着设置到 对应的 基础信息里 + List outputsList = jobQueryByUuidReturn.getData().getRobotParams().getOutputs(); + if (resultBoolean && ObjectUtil.isNotEmpty(outputsList)) { + Map resultObjMap = outputsList.stream().collect(Collectors.toMap(ResultObj::getName, ResultObj::getValue)); + CtClickOrder ctClickOrder = BeanUtil.mapToBean(resultObjMap, CtClickOrder.class, false); + if (ObjectUtil.isNotEmpty(ctClickOrder)) { + if (ObjectUtil.isNotEmpty(ctClickOrder.getPaymentResults()) && "Awaiting payment".equals(ctClickOrder.getPaymentResults())) { + status = ClickFarmingStatusEnum.AWAITING_PAYMENT.value(); + } + // 设置订单 公司 平台信息 + ctClickOrder.setCompanyId(ctBuyer.getCompanyId()); + if (ctClickOrderService.save(ctClickOrder)) { + ctClickFarming.setCtClickOrderId(ctClickOrder.getId()); + } + } + }else { + // 解析json 返回错误类型 + status = analysisReturnJson(jobQueryByUuidReturn.getData().getRemark()); + } + + ctClickFarming.setStatus(status); + if (ClickFarmingStatusEnum.EXECUTION_FAILE.value().equals(status) || ClickFarmingStatusEnum.PAY_OK_ERROR.value().equals(status)) { + ctClickFarming.setResponse(jobQueryByUuidReturn.getData().getRemark()); + }else { + ctClickFarming.setResponse(jobQueryByUuidReturn.getData().getStatusName()); + } + resultBoolean = ctClickFarmingService.updateById(ctClickFarming); + } + + log.info("============刷单补录回调鉴权完成 开始执行对应的定时业务逻辑================end==="); + return Dto.returnResult(resultBoolean); + } + + + /** + * 解析json 区分错误类型 + * @param remark + * @return Integer + */ + private Integer analysisReturnJson(String remark) { + // 根据规则解析 + /** + 1.切换VPN + 2.关闭弹窗 + 3.清空浏览器 + 4.切换国家 + 5.登录 + 6.订单首页 + 6-1.添加银行卡 + 6-2.选择银行卡有效时间 + 7.获取订单信息-------------------支付成功:流程7行(包含) + 8.退出账号 + */ + if (ObjectUtil.isEmpty(remark) || !remark.contains("任务失败")) { + return ClickFarmingStatusEnum.EXECUTION_FAILE.value(); + } + + String modular = remark.substring(remark.indexOf(STAET_MODULAR) + 8, remark.indexOf(END_MODULAR)); + String lineNumber = remark.substring(remark.indexOf(END_MODULAR) + 3, remark.indexOf(END_LINE_NUMBER)); + + // 子模块可以忽略 + Integer modularInteger = 0; + Integer lineNumberInteger = 0; + if (ObjectUtil.isNotEmpty(modular)) { + if (modular.contains(".") && !modular.contains("-") ) { + modularInteger = Integer.valueOf(modular.substring(0, modular.indexOf("."))); + } else if (modular.contains("-")) { + modularInteger = Integer.valueOf(modular.split("-")[0]); + } + } + if (ObjectUtil.isNotEmpty(lineNumber)) { + lineNumberInteger = Integer.valueOf(lineNumber); + } + + if (modularInteger < 7) { + return ClickFarmingStatusEnum.AWAITING_PAYMENT.value(); + } else if(modularInteger == 7) { + if (lineNumberInteger < 7) { + return ClickFarmingStatusEnum.AWAITING_PAYMENT.value(); + } else { + return ClickFarmingStatusEnum.PAY_OK_ERROR.value(); + } + } else { + return ClickFarmingStatusEnum.PAY_OK_ERROR.value(); + } + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/ClickOrderCallBackController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/ClickOrderCallBackController.java new file mode 100644 index 0000000..d903379 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/ClickOrderCallBackController.java @@ -0,0 +1,151 @@ +package me.zhengjie.modules.group.controller.callbcak; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.Log; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.*; +import me.zhengjie.entity.quartz.JobQueryByUuidReturn; +import me.zhengjie.enums.BuyerOccupyStatusEnum; +import me.zhengjie.enums.ClickOrderStatusEnum; +import me.zhengjie.enums.TaskInfoEnum; +import me.zhengjie.service.CtApplyService; +import me.zhengjie.service.CtBuyerService; +import me.zhengjie.service.CtClickOrderService; +import me.zhengjie.service.YdQuartzService; +import me.zhengjie.utils.RedisUtils; +import me.zhengjie.utils.YdCallBackUtil; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.List; + +/** + * @Description + * 好评定时任务回调逻辑 + * 回调需要鉴权,鉴权是根据 accesskey accessKeySrect + * 我们应用确认之后 accesskey 和 Srect是确定的 + * + * @Date 2022-8-23 + * @Author rch + */ +@Slf4j +@Validated +@RequestMapping("/api/clickOrder") +@RestController +@Api(tags = "回调:速卖通刷单好评-影刀回调") +public class ClickOrderCallBackController { + + @Resource + private CtApplyService ctApplyService; + @Resource + private YdQuartzService ydQuartzService; + @Resource + private CtClickOrderService ctClickOrderService; + @Resource + private RedisUtils redisUtils; + @Resource + private CtBuyerService ctBuyerService; + + /** + * 速卖通刷单好评-好评回调 + */ + @ApiOperation("速卖通刷单好评-好评回调") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3700, message = "影刀回调参数空值异常!"), + @ApiResponse(code = 3701, message = "影刀回调鉴权异常!") + }) + @Log(value = "速卖通刷单好评-好评回调") + @PostMapping("/callback") + @AnonymousAccess + @Transactional(rollbackFor = Exception.class) + public Dto callback(@Valid @RequestBody String data, HttpServletRequest httpServletRequest){ + + // 根据task枚举获取 应用信息 取出 accessKey 和 accessKeySecret 用于鉴权 + YdCallBackUtil ydCallBackUtil = new YdCallBackUtil(); + CtApply ctApply = ctApplyService.getApplyByTaskAndMethod(TaskInfoEnum.WELL_RECEIVED.getTaskName(), TaskInfoEnum.WELL_RECEIVED.getMethodName()); + Dto dto = ydCallBackUtil.callback(httpServletRequest, ctApply, data); + if (!dto.success(dto)) { + return dto; + } + + // 执行自己的业务逻辑 + log.info("============刷单回调鉴权完成 开始执行对应的定时业务逻辑================begin="); + log.info("回调======data:" + data); + // 获取自己想要的数据 + ReturnObje returnObje = JSONUtil.toBean(data, ReturnObje.class); + // job ID + String jobUuid = returnObje.getJobUuid(); + + // TODO 回调会重试 这里注意保证幂等 + // TODO 所以需要对接方在业务层面保障幂等(可以根据jobUuid或者taskUuid进行幂等保障,视startJob时是指定应用和机器人模式还是指定任务模式) + String keyJobUuid = PublicConstant.getJobUuidKeyPrefix(jobUuid); + if (!redisUtils.setIfAbsent(keyJobUuid, DateUtil.now())) { + log.info("-刷单回调接口-幂等性:keyJobUuid:" + keyJobUuid); + return Dto.returnResult(true); + } + + log.info("====returnObje====:{}", JSONUtil.toJsonStr(returnObje)); + JobQueryByUuidReturn jobQueryByUuidReturn = ydQuartzService.queryJobUuid(returnObje.getJobUuid(), ctApply.getAccessKeyId(), ctApply.getAccessKeySecret()); + log.info("====jobQueryByUuidReturn====:{}", JSONUtil.toJsonStr(jobQueryByUuidReturn)); + List inputsList = jobQueryByUuidReturn.getData().getRobotParams().getInputs(); + // 获取id + String id = null; + String buyerName = null; + for (ResultObj resultObj:inputsList) { + if ("id".equals(resultObj.getName())) { + id = resultObj.getValue(); + } + + if ("account".equals(resultObj.getName())) { + buyerName = resultObj.getValue(); + } + } + + Integer status = ClickOrderStatusEnum.EXECUTION_FAILE.value(); + if ("finish".equals(jobQueryByUuidReturn.getData().getStatus())) { + status = ClickOrderStatusEnum.EXECUTION_SUCCESS.value(); + } + + // 执行失败 + Boolean resultBoolean = false; + if (ObjectUtil.isNotEmpty(id)) { + CtClickOrder ctClickOrder = new CtClickOrder(); + ctClickOrder.setId(Long.valueOf(id)); + ctClickOrder.setStatus(status); + ctClickOrder.setPaymentResults(jobQueryByUuidReturn.getData().getRemark()); + + // 获取买家信息并修改买家信息 + CtBuyer ctBuyer = ctBuyerService.getBuyerOccupyStatusLock(buyerName); + if (ObjectUtil.isNotEmpty(ctBuyer) && BuyerOccupyStatusEnum.OCCUPIED.value().equals(ctBuyer.getOccupyStatus())) { + ctBuyer.setOccupyStatus(BuyerOccupyStatusEnum.UN_OCCUPIED.value()); + resultBoolean = ctBuyerService.updateById(ctBuyer); + } + + // TODO 需要更新的字段 从这里获取影刀返回的 然后接着设置到 对应的 基础信息里 + if (resultBoolean) { + resultBoolean = ctClickOrderService.updateById(ctClickOrder); + } + } + + log.info("============刷单回调鉴权完成 开始执行对应的定时业务逻辑================end==="); + return Dto.returnResult(resultBoolean); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/CtbrowseCallBackController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/CtbrowseCallBackController.java new file mode 100644 index 0000000..f575b42 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/CtbrowseCallBackController.java @@ -0,0 +1,148 @@ +package me.zhengjie.modules.group.controller.callbcak; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.Log; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.*; +import me.zhengjie.entity.quartz.JobQueryByUuidReturn; +import me.zhengjie.enums.BuyerOccupyStatusEnum; +import me.zhengjie.enums.ClickOrderStatusEnum; +import me.zhengjie.enums.TaskInfoEnum; +import me.zhengjie.service.*; +import me.zhengjie.utils.RedisUtils; +import me.zhengjie.utils.YdCallBackUtil; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.List; + +/** + * @Description + * 浏览收藏定时任务回调逻辑 + * 回调需要鉴权,鉴权是根据 accesskey accessKeySrect + * 我们应用确认之后 accesskey 和 Srect是确定的 + * + * @Date 2022-8-23 + * @Author rch + */ +@Slf4j +@Validated +@RequestMapping("/api/ctBrowse") +@RestController +@Api(tags = "回调:速卖通浏览收藏-影刀回调") +public class CtbrowseCallBackController { + + @Resource + private CtApplyService ctApplyService; + @Resource + private YdQuartzService ydQuartzService; + @Resource + private CtBrowseService ctBrowseService; + @Resource + private RedisUtils redisUtils; + @Resource + private CtBuyerService ctBuyerService; + + /** + * 速卖通刷单好评-好评回调 + */ + @ApiOperation("速卖通浏览收藏-回调") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3700, message = "影刀回调参数空值异常!"), + @ApiResponse(code = 3701, message = "影刀回调鉴权异常!") + }) + @Log(value = "速卖通浏览收藏-回调") + @PostMapping("/callback") + @AnonymousAccess + @Transactional(rollbackFor = Exception.class) + public Dto callback(@Valid @RequestBody String data, HttpServletRequest httpServletRequest){ + + // 根据task枚举获取 应用信息 取出 accessKey 和 accessKeySecret 用于鉴权 + YdCallBackUtil ydCallBackUtil = new YdCallBackUtil(); + CtApply ctApply = ctApplyService.getApplyByTaskAndMethod(TaskInfoEnum.BROWSE.getTaskName(), TaskInfoEnum.BROWSE.getMethodName()); + Dto dto = ydCallBackUtil.callback(httpServletRequest, ctApply, data); + if (!dto.success(dto)) { + return dto; + } + + // 执行自己的业务逻辑 + log.info("============刷单回调鉴权完成 开始执行对应的定时业务逻辑================begin="); + log.info("回调======data:" + data); + // 获取自己想要的数据 + ReturnObje returnObje = JSONUtil.toBean(data, ReturnObje.class); + // job ID + String jobUuid = returnObje.getJobUuid(); + + // TODO 回调会重试 这里注意保证幂等 + // TODO 所以需要对接方在业务层面保障幂等(可以根据jobUuid或者taskUuid进行幂等保障,视startJob时是指定应用和机器人模式还是指定任务模式) + String keyJobUuid = PublicConstant.getJobUuidKeyPrefix(jobUuid); + if (!redisUtils.setIfAbsent(keyJobUuid, DateUtil.now())) { + log.info("-刷单回调接口-幂等性:keyJobUuid:" + keyJobUuid); + return Dto.returnResult(true); + } + + log.info("====returnObje====:{}", JSONUtil.toJsonStr(returnObje)); + JobQueryByUuidReturn jobQueryByUuidReturn = ydQuartzService.queryJobUuid(returnObje.getJobUuid(), ctApply.getAccessKeyId(), ctApply.getAccessKeySecret()); + log.info("====jobQueryByUuidReturn====:{}", JSONUtil.toJsonStr(jobQueryByUuidReturn)); + List inputsList = jobQueryByUuidReturn.getData().getRobotParams().getInputs(); + // 获取id + String id = null; + String buyerName = null; + for (ResultObj resultObj:inputsList) { + if ("id".equals(resultObj.getName())) { + id = resultObj.getValue(); + } + + if ("account".equals(resultObj.getName())) { + buyerName = resultObj.getValue(); + } + } + + Integer status = ClickOrderStatusEnum.EXECUTION_FAILE.value(); + if ("finish".equals(jobQueryByUuidReturn.getData().getStatus())) { + status = ClickOrderStatusEnum.EXECUTION_SUCCESS.value(); + } + + // 执行失败 + Boolean resultBoolean = false; + if (ObjectUtil.isNotEmpty(id)) { + CtBrowse ctBrowse = new CtBrowse(); + ctBrowse.setId(Long.valueOf(id)); + ctBrowse.setStatus(status); + ctBrowse.setPaymentResults(jobQueryByUuidReturn.getData().getRemark()); + + // 获取买家信息并修改买家信息 + CtBuyer ctBuyer = ctBuyerService.getBuyerOccupyStatusLock(buyerName); + if (ObjectUtil.isNotEmpty(ctBuyer) && BuyerOccupyStatusEnum.OCCUPIED.value().equals(ctBuyer.getOccupyStatus())) { + ctBuyer.setOccupyStatus(BuyerOccupyStatusEnum.UN_OCCUPIED.value()); + resultBoolean = ctBuyerService.updateById(ctBuyer); + } + + // TODO 需要更新的字段 从这里获取影刀返回的 然后接着设置到 对应的 基础信息里 + if (resultBoolean) { + resultBoolean = ctBrowseService.updateById(ctBrowse); + } + } + + log.info("============刷单回调鉴权完成 开始执行对应的定时业务逻辑================end==="); + return Dto.returnResult(resultBoolean); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/DhAddCarCallBackController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/DhAddCarCallBackController.java new file mode 100644 index 0000000..e133d6a --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/DhAddCarCallBackController.java @@ -0,0 +1,152 @@ +package me.zhengjie.modules.group.controller.callbcak; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.Log; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.*; +import me.zhengjie.entity.quartz.JobQueryByUuidReturn; +import me.zhengjie.enums.BuyerOccupyStatusEnum; +import me.zhengjie.enums.ClickFarmingStatusEnum; +import me.zhengjie.enums.DhAddCarStatusEnum; +import me.zhengjie.enums.TaskInfoEnum; +import me.zhengjie.service.*; +import me.zhengjie.utils.RedisUtils; +import me.zhengjie.utils.YdCallBackUtil; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.List; + +/** + * @Description + * 敦煌加购定时任务回调逻辑 + * 回调需要鉴权,鉴权是根据 accesskey accessKeySrect + * 我们应用确认之后 accesskey 和 Srect是确定的 + * + * @Date 2022-8-23 + * @Author rch + */ +@Slf4j +@Validated +@RequestMapping("/api/dhAddCar") +@RestController +@Api(tags = "回调:敦煌加购-影刀回调") +public class DhAddCarCallBackController { + + @Resource + private CtApplyService ctApplyService; + @Resource + private YdQuartzService ydQuartzService; + @Resource + private DhAddCarService dhAddCarService; + @Resource + private DhAddCarOrderService dhAddCarOrderService; + @Resource + private RedisUtils redisUtils; + @Resource + private CtBuyerService ctBuyerService; + /** + * 敦煌加购-影刀回调 + */ + @ApiOperation("敦煌加购-影刀回调") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3700, message = "影刀回调参数空值异常!"), + @ApiResponse(code = 3701, message = "影刀回调鉴权异常!") + }) + @Log(value = "敦煌加购-影刀回调") + @PostMapping("/callback") + @AnonymousAccess + @Transactional(rollbackFor = Exception.class) + public Dto callback(@Valid @RequestBody String data, HttpServletRequest httpServletRequest){ + + // 根据task枚举获取 应用信息 取出 accessKey 和 accessKeySecret 用于鉴权 + YdCallBackUtil ydCallBackUtil = new YdCallBackUtil(); + CtApply ctApply = ctApplyService.getApplyByTaskAndMethod(TaskInfoEnum.DH_ADD_CAR_FARMING.getTaskName(), TaskInfoEnum.DH_ADD_CAR_FARMING.getMethodName()); + Dto dto = ydCallBackUtil.callback(httpServletRequest, ctApply, data); + if (!dto.success(dto)) { + return dto; + } + + // 执行自己的业务逻辑 + log.info("============敦煌加购回调鉴权完成 开始执行对应的定时业务逻辑================begin="); + log.info("回调======data:" + data); + // 获取自己想要的数据 + ReturnObje returnObje = JSONUtil.toBean(data, ReturnObje.class); + // job ID + String jobUuid = returnObje.getJobUuid(); + + // TODO 回调会重试 这里注意保证幂等 + // TODO 所以需要对接方在业务层面保障幂等(可以根据jobUuid或者taskUuid进行幂等保障,视startJob时是指定应用和机器人模式还是指定任务模式) + String keyJobUuid = PublicConstant.getJobUuidKeyPrefix(jobUuid); + if (!redisUtils.setIfAbsent(keyJobUuid, DateUtil.now())) { + log.info("-敦煌加购回调接口-幂等性:keyJobUuid:" + keyJobUuid); + return Dto.returnResult(true); + } + + log.info("====returnObje====:{}", JSONUtil.toJsonStr(returnObje)); + JobQueryByUuidReturn jobQueryByUuidReturn = ydQuartzService.queryJobUuid(returnObje.getJobUuid(), ctApply.getAccessKeyId(), ctApply.getAccessKeySecret()); + log.info("====jobQueryByUuidReturn====:{}", JSONUtil.toJsonStr(jobQueryByUuidReturn)); + List inputsList = jobQueryByUuidReturn.getData().getRobotParams().getInputs(); + // 获取id + String id = null; + String buyerName = null; + for (ResultObj resultObj:inputsList) { + if ("id".equals(resultObj.getName())) { + id = resultObj.getValue(); + } + if ("account".equals(resultObj.getName())) { + buyerName = resultObj.getValue(); + } + } + + Integer status = DhAddCarStatusEnum.ADD_CARD_FAILE.value(); + if ("finish".equals(jobQueryByUuidReturn.getData().getStatus())) { + status = DhAddCarStatusEnum.Add_CARD_SUCCESS.value(); + } + + // 执行失败 + Boolean resultBoolean = false; + if (ObjectUtil.isNotEmpty(id)) { + DhAddCar dhAddCar = new DhAddCar(); + dhAddCar.setId(Long.valueOf(id)); + + // 获取买家信息并修改买家信息 + CtBuyer ctBuyer = ctBuyerService.getBuyerOccupyStatusLock(buyerName); + if (ObjectUtil.isNotEmpty(ctBuyer) && BuyerOccupyStatusEnum.OCCUPIED.value().equals(ctBuyer.getOccupyStatus())) { + ctBuyer.setOccupyStatus(BuyerOccupyStatusEnum.UN_OCCUPIED.value()); + resultBoolean = ctBuyerService.updateById(ctBuyer); + } + + if (resultBoolean) { + dhAddCar.setStatus(status); + if (ClickFarmingStatusEnum.EXECUTION_FAILE.value().equals(status)) { + dhAddCar.setResponse(jobQueryByUuidReturn.getData().getRemark()); + }else { + dhAddCar.setResponse(jobQueryByUuidReturn.getData().getStatusName()); + } + resultBoolean = dhAddCarService.updateById(dhAddCar); + } + } + + log.info("============敦煌加购回调鉴权完成 开始执行对应的定时业务逻辑================end==="); + return Dto.returnResult(resultBoolean); + } +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/DhCarOrderCallBackController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/DhCarOrderCallBackController.java new file mode 100644 index 0000000..3cc8364 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/DhCarOrderCallBackController.java @@ -0,0 +1,170 @@ +package me.zhengjie.modules.group.controller.callbcak; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.Log; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.*; +import me.zhengjie.entity.quartz.JobQueryByUuidReturn; +import me.zhengjie.enums.BuyerOccupyStatusEnum; +import me.zhengjie.enums.ClickOrderStatusEnum; +import me.zhengjie.enums.DhAddCarStatusEnum; +import me.zhengjie.enums.TaskInfoEnum; +import me.zhengjie.service.CtApplyService; +import me.zhengjie.service.CtBuyerService; +import me.zhengjie.service.DhAddCarOrderService; +import me.zhengjie.service.YdQuartzService; +import me.zhengjie.utils.RedisUtils; +import me.zhengjie.utils.YdCallBackUtil; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @Description + * 敦煌加购好评定时任务回调逻辑 + * 回调需要鉴权,鉴权是根据 accesskey accessKeySrect + * 我们应用确认之后 accesskey 和 Srect是确定的 + * + * @Date 2022-8-23 + * @Author rch + */ +@Slf4j +@Validated +@RequestMapping("/api/dhCarOrder") +@RestController +@Api(tags = "回调:敦煌加购好评-影刀回调") +public class DhCarOrderCallBackController { + + @Resource + private CtApplyService ctApplyService; + @Resource + private YdQuartzService ydQuartzService; + @Resource + private DhAddCarOrderService dhAddCarOrderService; + @Resource + private RedisUtils redisUtils; + @Resource + private CtBuyerService ctBuyerService; + + /** + * 速卖通刷单好评-好评回调 + */ + @ApiOperation("速卖通刷单好评-好评回调") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3700, message = "影刀回调参数空值异常!"), + @ApiResponse(code = 3701, message = "影刀回调鉴权异常!") + }) + @Log(value = "敦煌加购好评-好评回调") + @PostMapping("/callback") + @AnonymousAccess + @Transactional(rollbackFor = Exception.class) + public Dto callback(@Valid @RequestBody String data, HttpServletRequest httpServletRequest){ + + // 根据task枚举获取 应用信息 取出 accessKey 和 accessKeySecret 用于鉴权 + YdCallBackUtil ydCallBackUtil = new YdCallBackUtil(); + CtApply ctApply = ctApplyService.getApplyByTaskAndMethod(TaskInfoEnum.DH_WELL_RECEIVED.getTaskName(), TaskInfoEnum.DH_WELL_RECEIVED.getMethodName()); + Dto dto = ydCallBackUtil.callback(httpServletRequest, ctApply, data); + if (!dto.success(dto)) { + return dto; + } + + // 执行自己的业务逻辑 + log.info("============刷单回调鉴权完成 开始执行对应的定时业务逻辑================begin="); + log.info("回调======data:" + data); + // 获取自己想要的数据 + ReturnObje returnObje = JSONUtil.toBean(data, ReturnObje.class); + // job ID + String jobUuid = returnObje.getJobUuid(); + + // TODO 回调会重试 这里注意保证幂等 + // TODO 所以需要对接方在业务层面保障幂等(可以根据jobUuid或者taskUuid进行幂等保障,视startJob时是指定应用和机器人模式还是指定任务模式) + String keyJobUuid = PublicConstant.getJobUuidKeyPrefix(jobUuid); + if (!redisUtils.setIfAbsent(keyJobUuid, DateUtil.now())) { + log.info("-刷单回调接口-幂等性:keyJobUuid:" + keyJobUuid); + return Dto.returnResult(true); + } + + log.info("====returnObje====:{}", JSONUtil.toJsonStr(returnObje)); + JobQueryByUuidReturn jobQueryByUuidReturn = ydQuartzService.queryJobUuid(returnObje.getJobUuid(), ctApply.getAccessKeyId(), ctApply.getAccessKeySecret()); + log.info("====jobQueryByUuidReturn====:{}", JSONUtil.toJsonStr(jobQueryByUuidReturn)); + List inputsList = jobQueryByUuidReturn.getData().getRobotParams().getInputs(); + // 获取id + String id = null; + String buyerName = null; + for (ResultObj resultObj:inputsList) { + if ("id".equals(resultObj.getName())) { + id = resultObj.getValue(); + } + + if ("account".equals(resultObj.getName())) { + buyerName = resultObj.getValue(); + } + } + + Integer status = ClickOrderStatusEnum.EXECUTION_FAILE.value(); + if ("finish".equals(jobQueryByUuidReturn.getData().getStatus())) { + status = ClickOrderStatusEnum.EXECUTION_SUCCESS.value(); + } + + // 执行失败 + Boolean resultBoolean = false; + if (ObjectUtil.isNotEmpty(id)) { + DhAddCarOrder dhAddCarOrder = new DhAddCarOrder(); + dhAddCarOrder.setId(Long.valueOf(id)); + dhAddCarOrder.setStatus(status); + + // 获取买家信息并修改买家信息 + CtBuyer ctBuyer = ctBuyerService.getBuyerOccupyStatusLock(buyerName); + if (ObjectUtil.isNotEmpty(ctBuyer) && BuyerOccupyStatusEnum.OCCUPIED.value().equals(ctBuyer.getOccupyStatus())) { + ctBuyer.setOccupyStatus(BuyerOccupyStatusEnum.UN_OCCUPIED.value()); + resultBoolean = ctBuyerService.updateById(ctBuyer); + } + + // TODO 需要更新的字段 从这里获取影刀返回的 然后接着设置到 对应的 基础信息里 + List outputsList = jobQueryByUuidReturn.getData().getRobotParams().getOutputs(); + if (ObjectUtil.isNotEmpty(outputsList)) { + Map resultObjMap = outputsList.stream().collect(Collectors.toMap(ResultObj::getName, ResultObj::getValue)); + if (ObjectUtil.isNotEmpty(resultObjMap.containsKey("receipt"))) { + dhAddCarOrder.setPaymentResults(resultObjMap.get("receipt")); + if ("success".equals(resultObjMap.get("receipt"))) { + status = ClickOrderStatusEnum.EXECUTION_SUCCESS.value(); + } + } else { + status = ClickOrderStatusEnum.EXECUTION_FAILE.value(); + } + } else { + status = DhAddCarStatusEnum.CATCH_ORDER_FAILE.value(); + } + + // TODO 需要更新的字段 从这里获取影刀返回的 然后接着设置到 对应的 基础信息里 + if (resultBoolean) { + dhAddCarOrder.setStatus(status); + resultBoolean = dhAddCarOrderService.updateById(dhAddCarOrder); + } + } + + log.info("============刷单回调鉴权完成 开始执行对应的定时业务逻辑================end==="); + return Dto.returnResult(resultBoolean); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/DhCatchOrderCallBackController.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/DhCatchOrderCallBackController.java new file mode 100644 index 0000000..bc9fc22 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/controller/callbcak/DhCatchOrderCallBackController.java @@ -0,0 +1,166 @@ +package me.zhengjie.modules.group.controller.callbcak; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.Log; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.*; +import me.zhengjie.entity.quartz.JobQueryByUuidReturn; +import me.zhengjie.enums.BuyerOccupyStatusEnum; +import me.zhengjie.enums.DhAddCarStatusEnum; +import me.zhengjie.enums.OrderTypeEnum; +import me.zhengjie.enums.TaskInfoEnum; +import me.zhengjie.service.*; +import me.zhengjie.utils.RedisUtils; +import me.zhengjie.utils.YdCallBackUtil; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @Description + * 敦煌-加购-抓单定时任务回调逻辑 + * 回调需要鉴权,鉴权是根据 accesskey accessKeySrect + * 我们应用确认之后 accesskey 和 Srect是确定的 + * + * @Date 2022-8-23 + * @Author rch + */ +@Slf4j +@Validated +@RequestMapping("/api/catchOrder") +@RestController +@Api(tags = "回调:敦煌抓单-影刀回调") +public class DhCatchOrderCallBackController { + + @Resource + private CtApplyService ctApplyService; + @Resource + private YdQuartzService ydQuartzService; + @Resource + private DhAddCarService dhAddCarService; + @Resource + private DhAddCarOrderService dhAddCarOrderService; + @Resource + private RedisUtils redisUtils; + @Resource + private CtBuyerService ctBuyerService; + + /** + * 敦煌-加购抓单-影刀回调 + */ + @ApiOperation("敦煌-加购抓单-影刀回调") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "响应成功"), + @ApiResponse(code = 2000, message = "服务器开小差了....,请稍后再试!"), + @ApiResponse(code = 3700, message = "影刀回调参数空值异常!"), + @ApiResponse(code = 3701, message = "影刀回调鉴权异常!") + }) + @Log(value = "敦煌-加购抓单-影刀回调") + @PostMapping("/callback") + @AnonymousAccess + @Transactional(rollbackFor = Exception.class) + public Dto callback(@Valid @RequestBody String data, HttpServletRequest httpServletRequest){ + + // 根据task枚举获取 应用信息 取出 accessKey 和 accessKeySecret 用于鉴权 + YdCallBackUtil ydCallBackUtil = new YdCallBackUtil(); + CtApply ctApply = ctApplyService.getApplyByTaskAndMethod(TaskInfoEnum.DH_ADD_CAR_CATCH_ORDER.getTaskName(), TaskInfoEnum.DH_ADD_CAR_CATCH_ORDER.getMethodName()); + Dto dto = ydCallBackUtil.callback(httpServletRequest, ctApply, data); + if (!dto.success(dto)) { + return dto; + } + + // 执行自己的业务逻辑 + log.info("============刷单回调鉴权完成 开始执行对应的定时业务逻辑================begin="); + log.info("回调======data:" + data); + // 获取自己想要的数据 + ReturnObje returnObje = JSONUtil.toBean(data, ReturnObje.class); + // job ID + String jobUuid = returnObje.getJobUuid(); + + // TODO 回调会重试 这里注意保证幂等 + // TODO 所以需要对接方在业务层面保障幂等(可以根据jobUuid或者taskUuid进行幂等保障,视startJob时是指定应用和机器人模式还是指定任务模式) + String keyJobUuid = PublicConstant.getJobUuidKeyPrefix(jobUuid); + if (!redisUtils.setIfAbsent(keyJobUuid, DateUtil.now())) { + log.info("-刷单回调接口-幂等性:keyJobUuid:" + keyJobUuid); + return Dto.returnResult(true); + } + + log.info("====returnObje====:{}", JSONUtil.toJsonStr(returnObje)); + JobQueryByUuidReturn jobQueryByUuidReturn = ydQuartzService.queryJobUuid(returnObje.getJobUuid(), ctApply.getAccessKeyId(), ctApply.getAccessKeySecret()); + log.info("====jobQueryByUuidReturn====:{}", JSONUtil.toJsonStr(jobQueryByUuidReturn)); + List inputsList = jobQueryByUuidReturn.getData().getRobotParams().getInputs(); + // 获取id + String id = null; + String buyerName = null; + for (ResultObj resultObj:inputsList) { + if ("id".equals(resultObj.getName())) { + id = resultObj.getValue(); + } + + if ("account".equals(resultObj.getName())) { + buyerName = resultObj.getValue(); + } + } + + Integer status = DhAddCarStatusEnum.CATCH_ORDER_FAILE.value(); + if ("finish".equals(jobQueryByUuidReturn.getData().getStatus())) { + status = DhAddCarStatusEnum.CATCH_ORDER_SUCCESS.value(); + } + + Boolean resultBoolean = false; + if (ObjectUtil.isNotEmpty(id)) { + DhAddCar dhAddCar = new DhAddCar(); + dhAddCar.setId(Long.valueOf(id)); + + // 获取买家信息并修改买家信息 + CtBuyer ctBuyer = ctBuyerService.getBuyerOccupyStatusLock(buyerName); + if (ObjectUtil.isNotEmpty(ctBuyer) && BuyerOccupyStatusEnum.OCCUPIED.value().equals(ctBuyer.getOccupyStatus())) { + ctBuyer.setOccupyStatus(BuyerOccupyStatusEnum.UN_OCCUPIED.value()); + resultBoolean = ctBuyerService.updateById(ctBuyer); + } + + // TODO 需要更新的字段 从这里获取影刀返回的 然后接着设置到 对应的 基础信息里 + List outputsList = jobQueryByUuidReturn.getData().getRobotParams().getOutputs(); + if (ObjectUtil.isNotEmpty(outputsList)) { + Map resultObjMap = outputsList.stream().collect(Collectors.toMap(ResultObj::getName, ResultObj::getValue)); + DhAddCarOrder dhAddCarOrder = BeanUtil.mapToBean(resultObjMap, DhAddCarOrder.class, false); + if (ObjectUtil.isNotEmpty(dhAddCarOrder)) { + // 设置订单 公司 平台信息 + dhAddCarOrder.setType(OrderTypeEnum.CLICK_FARMING.value()); + if (dhAddCarOrderService.save(dhAddCarOrder)) { + dhAddCarOrder.setAddCarId(Long.valueOf(id)); + } + } + } else { + status = DhAddCarStatusEnum.CATCH_ORDER_FAILE.value(); + } + + dhAddCar.setResponse(jobQueryByUuidReturn.getData().getStatusName()); + dhAddCar.setStatus(status); + resultBoolean = dhAddCarService.updateById(dhAddCar); + } + + log.info("============敦煌-加购抓单-回调鉴权完成 开始执行对应的定时业务逻辑================end==="); + return Dto.returnResult(resultBoolean); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtApplyAddDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtApplyAddDTO.java new file mode 100644 index 0000000..5f665af --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtApplyAddDTO.java @@ -0,0 +1,57 @@ +package me.zhengjie.modules.group.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * 应用信息(ct_apply)新增 DTO + * + * Author zhw + * Data 2022-07-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel(description="添加应用信息") +public class CtApplyAddDTO { + + /** 应用名称 */ + @NotNull + @ApiModelProperty(value = "应用名称", required = true) + private String name; + + /** 任务名称 */ + @NotNull + @ApiModelProperty(value = "任务名称", required = true) + private String taskName; + + /** 方法名称 */ + @ApiModelProperty(value = "方法名称") + private String methodName; + + /** accessKeyId */ + @NotNull + @ApiModelProperty(value = "accessKeyId", required = true) + private String accessKeyId; + + /** accessKeySecret */ + @NotNull + @ApiModelProperty(value = "accessKeySecret", required = true) + private String accessKeySecret; + + /** 应用id */ + @NotNull + @ApiModelProperty(value = "应用id", required = true) + private String robotUuid; + + /** 备注 */ + @NotNull + @ApiModelProperty(value = "备注", required = true) + private String remark; + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtApplyListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtApplyListDTO.java new file mode 100644 index 0000000..4347328 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtApplyListDTO.java @@ -0,0 +1,43 @@ +package me.zhengjie.modules.group.dto; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.CtApply; + + +/** + * @Description 分页查询 应用信息 + * @Date 2022/7/23 + * @Author zhw + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("查询用户") +public class CtApplyListDTO extends PageDTO { + + /** 应用名称 */ + @ApiModelProperty(value = "应用名称") + private String name; + /** 应用id */ + @ApiModelProperty(value = "应用id") + private String robotUuid; + + public Wrapper getWrapper(){ + QueryWrapper qw = new QueryWrapper<>(); + qw + .like(ObjectUtil.isNotEmpty(name),"name",name) + .like(ObjectUtil.isNotEmpty(robotUuid),"robot_uuid", robotUuid) + .orderBy(ObjectUtil.isNotEmpty(getSort()),isAsc(),getSort()) + .orderByDesc("id") + ; + return qw; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtApplyUpdateDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtApplyUpdateDTO.java new file mode 100644 index 0000000..f5476ce --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtApplyUpdateDTO.java @@ -0,0 +1,54 @@ +package me.zhengjie.modules.group.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * 应用信息(ct_apply)修改 DTO + * + * Author zhw + * Data 2022-07-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("修改应用") +public class CtApplyUpdateDTO { + + @NotNull + @ApiModelProperty(value = "id", required = true) + private Long id; + + /** 应用名称 */ + @ApiModelProperty(value = "应用名称") + private String name; + + /** 任务名称 */ + @ApiModelProperty(value = "任务名称") + private String taskName; + + /** 方法名称 */ + @ApiModelProperty(value = "方法名称") + private String methodName; + + /** accessKeyId */ + @ApiModelProperty(value = "accessKeyId") + private String accessKeyId; + + /** accessKeySecret */ + @ApiModelProperty(value = "accessKeySecret") + private String accessKeySecret; + + /** 应用id */ + @ApiModelProperty(value = "应用id") + private String robotUuid; + + /** 备注 */ + @ApiModelProperty(value = "备注") + private String remark; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBrowseAddDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBrowseAddDTO.java new file mode 100644 index 0000000..f99b236 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBrowseAddDTO.java @@ -0,0 +1,33 @@ +package me.zhengjie.modules.group.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * 浏览收藏信息 DTO + * + * @author rch + * @create 2022-11-04 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("新增浏览收藏") +public class CtBrowseAddDTO { + + /** 买家ID */ + @NotNull + @ApiModelProperty(value = "买家ID", required = true) + private Long buyerId; + + /** 收藏链接 */ + @NotNull + @ApiModelProperty(value = "收藏链接", required = true) + private String linkUrl; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBrowseListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBrowseListDTO.java new file mode 100644 index 0000000..7b8a80e --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBrowseListDTO.java @@ -0,0 +1,57 @@ +package me.zhengjie.modules.group.dto; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.CtBuyer; +import me.zhengjie.enums.ClickBrowseStatusEnum; +import me.zhengjie.enums.ClickFarmingStatusEnum; +import me.zhengjie.enums.ClickOrderStatusEnum; + +import java.util.Arrays; +import java.util.Date; + + +/** + * @Description 分页查询 浏览刷单 + * @Date 2022-11-04 + * @Author rch + */ +@Data +@ApiModel("分页查询浏览刷单") +public class CtBrowseListDTO extends PageDTO { + + /** 账号 */ + @ApiModelProperty(value = "账号") + private String account; + + /** 收藏链接 */ + @ApiModelProperty(value = "收藏链接") + private String linkUrl; + + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 */ + @ApiModelProperty(value = "状态 1.待执行 2.执行中 3.执行成功 4.执行失败", allowableValues = "1,2,3,4") + private Integer status; + + @ApiModelProperty(value = "是否是仅查询可以执行的浏览收藏") + private Integer inStatusList; + + public Wrapper getWrapper() { + QueryWrapper qw = new QueryWrapper(); + qw + .eq(ObjectUtil.isNotEmpty(account), "ctBuyer.account", account) + .eq(ObjectUtil.isNotEmpty(linkUrl), "ctBrowse.link_url", linkUrl) + .eq(ObjectUtil.isNotEmpty(status), "ctBrowse.status", status) + .in(ObjectUtil.isNotEmpty(inStatusList), "ctBrowse.status", Arrays.asList(ClickBrowseStatusEnum.TOBE_EXECUTION.value(), ClickBrowseStatusEnum.EXECUTION_FAILE.value())) + .orderBy(ObjectUtil.isNotEmpty(getSort()), isAsc(), getSort()) + .orderByDesc("ctBrowse.updated_at") + ; + + return qw; + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBrowseUpdateDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBrowseUpdateDTO.java new file mode 100644 index 0000000..3859d1a --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBrowseUpdateDTO.java @@ -0,0 +1,46 @@ +package me.zhengjie.modules.group.dto; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + + +/** + * 修改浏览收藏 + * + * @author rch + * @create 2022-11-04 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("修改浏览收藏") +public class CtBrowseUpdateDTO { + + @NotNull + @ApiModelProperty(value = "id") + private Long id; + + /** 买家ID */ + @ApiModelProperty(value = "买家ID") + private Long buyerId; + + /** 收藏链接 */ + @ApiModelProperty(value = "收藏链接") + private String linkUrl; + + /** 状态描述 */ + @ApiModelProperty(value = "状态描述") + private String paymentResults; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBuyerAddDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBuyerAddDTO.java new file mode 100644 index 0000000..97ed46d --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBuyerAddDTO.java @@ -0,0 +1,135 @@ +package me.zhengjie.modules.group.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +/** + * 买家信息 DTO + * + * @author rch + * @create 2022-06-22 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("新增买家") +public class CtBuyerAddDTO { + + /** 昵称*/ + @NotNull + @ApiModelProperty(value = "昵称", required = true) + private String nickName; + + /** 账号*/ + @NotNull + @ApiModelProperty(value = "账号", required = true) + private String account; + + /** 密码*/ + @NotNull + @ApiModelProperty(value = "密码", required = true) + private String pwd; + + /** 公司id */ + @NotNull + @ApiModelProperty(value = "公司id", required = true) + private Long companyId; + + /** 平台id */ + @NotNull + @ApiModelProperty(value = "平台id", required = true) + private Integer platformId; + + ////////////////////////////////////// 新增字段 + /** 国家 */ + @NotNull + @ApiModelProperty(value = "国家", required = true) + private String contntryShort; + + /** VPN_ID(导入excel里包含) */ + @NotNull + @ApiModelProperty(value = "VPN_ID", required = true) + private Long vpnId; + + /** 信用卡ID */ + @ApiModelProperty(value = "信用卡ID", required = true) + private Long cardId; + + /** 用户等级(导入默认内部账号) 1.普通 2.精品 3.压力 4.内部账号 */ + @NotNull + @Min(1) + @Max(4) + @ApiModelProperty(value = "用户等级(导入默认内部账号) 1.普通 2.精品 3.压力 4.内部账号", required = true, allowableValues = "1,2,3,4") + private Integer level; + + /** 占用状态 1.已占用 2.未占用 */ + @NotNull + @Min(1) + @Max(2) + @ApiModelProperty(value = "占用状态 1.已占用 2.未占用", required = true, allowableValues = "1,2") + private Integer occupyStatus; + + /** 状态(导入默认正常) 1.待注册 2待验证 3.待完善 4.正常 5.异常 6.可用但已用 7.删除 */ + @NotNull + @Min(1) + @Max(7) + @ApiModelProperty(value = "状态(导入默认正常) 1.待注册 2待验证 3.待完善 4.正常 5.异常 6.可用但已用 7.删除", required = true, allowableValues = "1,2,3,4,5,6,7") + private Integer status; + + // ==================地址信息相关========================================begin + /** 地址1 */ + @NotNull + @ApiModelProperty(value = "地址1", required = true) + private String addressline1; + + /** 国家 */ + @NotNull + @ApiModelProperty(value = "国家", required = true) + private String country; + + /** 州 */ + @NotNull + @ApiModelProperty(value = "州", required = true) + private String state; + + /** 电话 */ + @NotNull + @ApiModelProperty(value = "电话", required = true) + private String tel; + + /** lastname */ + @NotNull + @ApiModelProperty(value = "lastname", required = true) + private String lastname; + + /** 税号 */ + @ApiModelProperty(value = "税号") + private String vatNumber; + + /** 城市 */ + @NotNull + @ApiModelProperty(value = "城市", required = true) + private String city; + + /** 地址2 */ + @ApiModelProperty(value = "地址2") + private String addressline2; + + /** firstname */ + @NotNull + @ApiModelProperty(value = "firstname", required = true) + private String firstname; + + /** 邮政编码 */ + @NotNull + @ApiModelProperty(value = "邮政编码", required = true) + private String postalcode; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBuyerListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBuyerListDTO.java new file mode 100644 index 0000000..9c6dc08 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBuyerListDTO.java @@ -0,0 +1,57 @@ +package me.zhengjie.modules.group.dto; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.CtBuyer; + + +/** + * @Description 分页查询 买家信息 + * @Date 2022-06-22 + * @Author rch + */ +@Data +@ApiModel("查询买家") +public class CtBuyerListDTO extends PageDTO { + + /** 昵称*/ + @ApiModelProperty(value = "昵称") + private String nickName; + + /** 账号*/ + @ApiModelProperty(value = "账号") + private String account; + + /** 姓名 */ + @ApiModelProperty(value = "姓名") + private String pwd; + + /** 平台id */ + @ApiModelProperty(value = "平台id") + private Integer platformId; + + /** 公司id */ + @ApiModelProperty(value = "公司id") + private Long companyId; + + public Wrapper getWrapper() { + QueryWrapper qw = new QueryWrapper(); + qw + .eq(ObjectUtil.isNotEmpty(platformId), "t1.platform_id", platformId) + .eq(ObjectUtil.isNotEmpty(companyId), "t1.company_id", companyId) + .like(ObjectUtil.isNotEmpty(nickName), "t1.nick_name", nickName) + .like(ObjectUtil.isNotEmpty(account), "t1.account", account) + .like(ObjectUtil.isNotEmpty(pwd), "t1.pwd", pwd) + .orderBy(ObjectUtil.isNotEmpty(getSort()), isAsc(), getSort()) + .orderByDesc("updated_at") + ; + + return qw; + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBuyerUpdateDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBuyerUpdateDTO.java new file mode 100644 index 0000000..9bd28c2 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtBuyerUpdateDTO.java @@ -0,0 +1,122 @@ +package me.zhengjie.modules.group.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + + +/** + * 修改 买家 + * + * @author rch + * @create 2022-06-22 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("编辑买家") +public class CtBuyerUpdateDTO { + + @NotNull + @ApiModelProperty(value = "Id", required = true) + private Integer id; + + /** 公司id */ + @ApiModelProperty(value = "公司id") + private Long companyId; + + /** 平台id */ + @ApiModelProperty(value = "平台id") + private Integer platformId; + + /** 昵称 */ + @ApiModelProperty(value = "昵称") + private String nickName; + + /** 账号 */ + @ApiModelProperty(value = "账号") + private String account; + + /** 密码 */ + @ApiModelProperty(value = "密码") + private String pwd; + + ////////////////////////////////////// 新增字段 + /** 国家 */ + @ApiModelProperty(value = "国家") + private String contntryShort; + + /** VPN_ID(导入excel里包含) */ + @ApiModelProperty(value = "VPN_ID") + private Long vpnId; + + /** 信用卡ID */ + @ApiModelProperty(value = "信用卡ID") + private Long cardId; + + /** 用户等级(导入默认内部账号) 1.普通 2.精品 3.压力 4.内部账号 */ + @Min(1) + @Max(4) + @ApiModelProperty(value = "用户等级(导入默认内部账号) 1.普通 2.精品 3.压力 4.内部账号", allowableValues = "1,2,3,4") + private Integer level; + + /** 占用状态 1.已占用 2.未占用 */ + @Min(1) + @Max(2) + @ApiModelProperty(value = "占用状态 1.已占用 2.未占用", allowableValues = "1,2") + private Integer occupyStatus; + + /** 状态(导入默认正常) 1.待注册 2待验证 3.待完善 4.正常 5.异常 6.可用但已用 7.删除 */ + @Min(1) + @Max(7) + @ApiModelProperty(value = "状态(导入默认正常) 1.待注册 2待验证 3.待完善 4.正常 5.异常 6.可用但已用 7.删除", allowableValues = "1,2,3,4,5,6,7") + private Integer status; + + // ==================地址信息相关========================================begin + /** 地址1 */ + @ApiModelProperty(value = "地址1") + private String addressline1; + + /** 国家 */ + @ApiModelProperty(value = "国家") + private String country; + + /** 州 */ + @ApiModelProperty(value = "州") + private String state; + + /** 电话 */ + @ApiModelProperty(value = "电话") + private String tel; + + /** lastname */ + @ApiModelProperty(value = "lastname") + private String lastname; + + /** 税号 */ + @ApiModelProperty(value = "税号") + private String vatNumber; + + /** 城市 */ + @ApiModelProperty(value = "城市") + private String city; + + /** 地址2 */ + @ApiModelProperty(value = "地址2") + private String addressline2; + + /** firstname */ + @ApiModelProperty(value = "firstname") + private String firstname; + + /** 邮政编码 */ + @ApiModelProperty(value = "邮政编码") + private String postalcode; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCardAddDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCardAddDTO.java new file mode 100644 index 0000000..8cba632 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCardAddDTO.java @@ -0,0 +1,105 @@ +package me.zhengjie.modules.group.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.Date; + +/** + * 信用卡信息 DTO + * + * @author rch + * @create 2022-07-09 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("新增信用卡") +public class CtCardAddDTO { + + /** 父ID */ + // private Long parentId; + + /** 卡号 */ + @NotBlank + @ApiModelProperty(value = "卡号", required = true) + private String number; + +// /** PIN码 */ +// @NotBlank +// @ApiModelProperty(value = "PIN码", required = true) +// private String pinNumber; + + /** 持卡人姓氏 */ + @NotBlank + @ApiModelProperty(value = "持卡人姓氏", required = true) + private String holderSurname; + + /** 持卡人名称 */ + @NotBlank + @ApiModelProperty(value = "持卡人名称", required = true) + private String holderName; + + /** 有效期 */ + @NotBlank + private String termOfValidity; + + /** 开卡日期 */ + // private Date openDate; + + /** 所属国家 */ + @ApiModelProperty(value = "所属国家", required = true) + private String contntryShort; + + /** 信用卡类型 1.Payoneer 2.万事达虚拟卡 3.Visa信用卡 */ + @NotNull + @Min(1) + @Max(3) + @ApiModelProperty(value = "信用卡类型 1.Payoneer 2.万事达虚拟卡 3.Visa信用卡", required = true, allowableValues = "1,2,3") + private Integer type; + + /** 所属厂商:1.AmzKeys 2.Airwallex */ + @NotNull + @Min(1) + @Max(2) + @ApiModelProperty(value = "所属厂商:1.AmzKeys 2.Airwallex", required = true, allowableValues = "1,2") + private Integer cardDealer; + + /** 身份证号 */ + // private String idNumber; + + /** 省份 */ + // private String province; + + /** 城市 */ + // private String country; + + /** 地址 */ + // private String address; + + /** 手机号 */ + // private String phone; + + /** 邮箱 */ + // private String email; + + /** 登陆账号 */ + // private String account; + + /** 密码 */ + @ApiModelProperty(value = "密码", required = true) + @NotNull + private String pwd; + + /** 备注 */ + @ApiModelProperty(value = "备注") + private String remarks; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCardListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCardListDTO.java new file mode 100644 index 0000000..bcb8320 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCardListDTO.java @@ -0,0 +1,62 @@ +package me.zhengjie.modules.group.dto; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.CtBuyer; + + +/** + * @Description 分页查询 信用卡 + * @Date 2022-07-9 + * @Author rch + */ +@Data +@ApiModel("分页查询信用卡") +public class CtCardListDTO extends PageDTO { + + /** 卡号 */ + @ApiModelProperty(value = "卡号") + private String number; + + /** PIN码 */ + @ApiModelProperty(value = "PIN码") + private String pinNumber; + + /** 持卡人名称 */ + @ApiModelProperty(value = "持卡人名称") + private String holderName; + + /** 信用卡类型 1.Payoneer 2.万事达虚拟卡 3.Visa信用卡 */ + @ApiModelProperty(value = "信用卡类型 1.Payoneer 2.万事达虚拟卡 3.Visa信用卡", allowableValues = "1,2,3") + private Integer type; + + /** 所属厂商:1.AmzKeys 2.Airwallex */ + @ApiModelProperty(value = "所属厂商:1.AmzKeys 2.Airwallex", allowableValues = "1,2") + private Integer cardDealer; + + /** 状态:1.正常、2.异常、3.已删除 */ + @ApiModelProperty(value = "状态:1.正常、2.异常、3.已删除", allowableValues = "1,2,3") + private Integer status; + + public Wrapper getWrapper() { + QueryWrapper qw = new QueryWrapper(); + qw + .eq(ObjectUtil.isNotEmpty(type), "type", type) + .eq(ObjectUtil.isNotEmpty(cardDealer), "card_dealer", cardDealer) + .eq(ObjectUtil.isNotEmpty(status), "status", status) + .like(ObjectUtil.isNotEmpty(number), "number", number) + .like(ObjectUtil.isNotEmpty(pinNumber), "pin_number", pinNumber) + .like(ObjectUtil.isNotEmpty(holderName), "holder_name", holderName) + .orderBy(ObjectUtil.isNotEmpty(getSort()), isAsc(), getSort()) + .orderByDesc("updated_at") + ; + + return qw; + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCardUpdateDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCardUpdateDTO.java new file mode 100644 index 0000000..c63831c --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCardUpdateDTO.java @@ -0,0 +1,75 @@ +package me.zhengjie.modules.group.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + + +/** + * 修改信用卡 + * + * @author rch + * @create 2022-06-22 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("修改信用卡") +public class CtCardUpdateDTO { + + @NotNull + @ApiModelProperty(value = "Id", required = true) + private Integer id; + + /** 卡号 */ + @ApiModelProperty(value = "卡号") + private String number; + +// /** PIN码 */ +// @ApiModelProperty(value = "PIN码") +// private String pinNumber; + + /** 持卡人姓氏 */ + @ApiModelProperty(value = "持卡人姓氏") + private String holderSurname; + + /** 持卡人名称 */ + @ApiModelProperty(value = "持卡人名称") + private String holderName; + + /** 有效期 */ + @ApiModelProperty(value = "有效期") + private String termOfValidity; + + /** 所属国家 */ + @ApiModelProperty(value = "所属国家") + private String contntryShort; + + /** 信用卡类型 1.Payoneer 2.万事达虚拟卡 3.Visa信用卡 */ + @Min(1) + @Max(3) + @ApiModelProperty(value = "信用卡类型 1.Payoneer 2.万事达虚拟卡 3.Visa信用卡", required = true, allowableValues = "1,2,3") + private Integer type; + + /** 所属厂商:1.AmzKeys 2.Airwallex */ + @Min(1) + @Max(2) + @ApiModelProperty(value = "所属厂商:1.AmzKeys 2.Airwallex", required = true, allowableValues = "1,2") + private Integer cardDealer; + + /** 密码 */ + @NotNull + @ApiModelProperty(value = "密码", required = true) + private String pwd; + + /** 备注 */ + @ApiModelProperty(value = "备注") + private String remarks; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickFarmingAddDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickFarmingAddDTO.java new file mode 100644 index 0000000..3ec971a --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickFarmingAddDTO.java @@ -0,0 +1,83 @@ +package me.zhengjie.modules.group.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import io.swagger.models.auth.In; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 刷单信息 DTO + * + * @author rch + * @create 2022-07-09 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("新增刷单信息") +public class CtClickFarmingAddDTO { + + @NotNull + /** 买家id */ + @ApiModelProperty(value = "买家id", required = true) + private Long buyerId; + + /** 店铺名称 */ + @ApiModelProperty(value = "店铺名称", required = true) + private String shopName; + + /** 刷单类型 */ + @NotNull + @ApiModelProperty(value = "商品属性类型:1.关键词 2.链接", required = true, allowableValues = "1,2") + private Integer paramsType; + + /** 关键词 */ + @ApiModelProperty(value = "关键词", required = true) + private String keyWord; + + /** 标题 */ + @ApiModelProperty(value = "标题", required = true) + private String title; + + /** 链接 */ + @ApiModelProperty(value = "链接", required = true) + private String link; + + /** 数量 */ + @ApiModelProperty(value = "数量", required = true) + private Integer number; + + /** 规格 */ + @ApiModelProperty(value = "规格") + private String specification; + + /** 颜色 */ + @ApiModelProperty(value = "颜色") + private String color; + + /** item */ + @ApiModelProperty(value = "item", required = true) + private String item; + + @ApiModelProperty(value = "exchange") + private String exchange; + + /** 最小价格区间 */ + @ApiModelProperty(value = "最小价格区间") + private String sectionMin; + + /** 最大价格区间 */ + @ApiModelProperty(value = "最大价格区间") + private String sectionMax; + + /** 留言 */ + @NotBlank + @ApiModelProperty(value = "留言", required = true) + private String amessage; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickFarmingDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickFarmingDTO.java new file mode 100644 index 0000000..5827d9b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickFarmingDTO.java @@ -0,0 +1,87 @@ +package me.zhengjie.modules.group.dto; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.CtBuyer; +import me.zhengjie.enums.ClickFarmingStatusEnum; + +import java.util.Arrays; +import java.util.List; + + +/** + * @Description 分页查询 刷单信息 + * @Date 2022-07-9 + * @Author rch + */ +@Data +@ApiModel("分页查询刷单信息") +public class CtClickFarmingDTO extends PageDTO { + + /** 关键词 */ + @ApiModelProperty(value = "关键词") + private String keyWord; + + /** Item */ + @ApiModelProperty(value = "Item") + private String item; + + /** 店铺名称 */ + @ApiModelProperty(value = "店铺名称") + private String shopName; + +// /** 刷单类型 */ +// private Integer type; + /** 刷单类型 */ + private Integer paramsType; + /** 国家 */ + private String country; + /** 账号 */ + private String account; + +// /** 平台类型 2.速卖通 1.敦煌*/ +// private Integer platformId; + + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 5.代付款 */ + @ApiModelProperty(value = "状态 1.待执行 2.执行中 3.执行成功 4.执行失败 5.代付款", allowableValues = "1,2,3,4,5") + private Integer status; + + @ApiModelProperty(value = "") + private List inStatusList; + + /** 支付订单ID */ + @ApiModelProperty(value = "支付订单ID") + private String payOrderId; + +// @ApiModelProperty(value = "是否是抓单 1.是 0.否") // ct_click_order_id +// private Integer inCatchorder; + + public Wrapper getWrapper() { + QueryWrapper qw = new QueryWrapper(); + qw +// .eq(ObjectUtil.isNotEmpty(type), "farming.type", type) + .eq(ObjectUtil.isNotEmpty(paramsType), "farming.params_type", paramsType) + .eq(ObjectUtil.isNotEmpty(country), "buyer.contntry_short", country) + .eq(ObjectUtil.isNotEmpty(account), "buyer.account", account) +// .eq(ObjectUtil.isNotEmpty(platformId), "buyer.platform_id", platformId) + .eq(ObjectUtil.isNotEmpty(status), "farming.status", status) +// .isNull(ObjectUtil.isNotEmpty(inCatchorder), "farming.ct_click_order_id") + .in(ObjectUtil.isNotEmpty(inStatusList), "farming.status", Arrays.asList(ClickFarmingStatusEnum.TOBE_EXECUTION.value(), ClickFarmingStatusEnum.EXECUTION_FAILE.value())) +// .in(ObjectUtil.isNotEmpty(inCatchorder), "farming.status", Arrays.asList(ClickFarmingStatusEnum.EXECUTION_SUCCESS.value(), ClickFarmingStatusEnum.EXECUTION_FAILE.value())) + .like(ObjectUtil.isNotEmpty(keyWord), "farming.key_word", keyWord) + .like(ObjectUtil.isNotEmpty(item), "farming.item", item) + .like(ObjectUtil.isNotEmpty(shopName), "farming.shop_name", shopName) + .like(ObjectUtil.isNotEmpty(payOrderId), "clickOrder.order_id", payOrderId) + .orderBy(ObjectUtil.isNotEmpty(getSort()), isAsc(), getSort()) + .orderByDesc("updated_at") + ; + + return qw; + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickFarmingEditDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickFarmingEditDTO.java new file mode 100644 index 0000000..a10d747 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickFarmingEditDTO.java @@ -0,0 +1,84 @@ +package me.zhengjie.modules.group.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 刷单信息 DTO + * + * @author rch + * @create 2022-07-09 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("刷单信息") +public class CtClickFarmingEditDTO { + + @NotNull + @ApiModelProperty(value = "Id", required = true) + private Long id; + + @ApiModelProperty(value = "buyerId") + @NotNull + private Long buyerId; + + /** 刷单类型 */ + @NotNull + @ApiModelProperty(value = "商品属性类型:1.关键词 2.链接", required = true, allowableValues = "1,2") + private Integer paramsType; + + /** 店铺名称 */ + @ApiModelProperty(value = "店铺名称") + private String shopName; + + /** 关键词 */ + @ApiModelProperty(value = "关键词") + private String keyWord; + + /** 标题 */ + @ApiModelProperty(value = "标题") + private String title; + + /** 链接 */ + @ApiModelProperty(value = "链接") + private String link; + + /** 数量 */ + @ApiModelProperty(value = "数量") + private Integer number; + + /** 规格 */ + @ApiModelProperty(value = "规格") + private String specification; + + /** 颜色 */ + @ApiModelProperty(value = "颜色") + private String color; + + /** item */ + @ApiModelProperty(value = "item") + private String item; + + @ApiModelProperty(value = "exchange") + private String exchange; + + /** 最小价格区间 */ + @ApiModelProperty(value = "最小价格区间") + private String sectionMin; + + /** 最大价格区间 */ + @ApiModelProperty(value = "最大价格区间") + private String sectionMax; + + /** 留言 */ + @ApiModelProperty(value = "留言") + private String amessage; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickOrderAddDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickOrderAddDto.java new file mode 100644 index 0000000..1e35345 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickOrderAddDto.java @@ -0,0 +1,71 @@ +package me.zhengjie.modules.group.dto; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * 刷单-订单评论信息 + * + * @author rch + * @since 2022-10-20 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("新增刷单订单评论") +public class CtClickOrderAddDto { + + /** 公司ID */ + @NotNull + @ApiModelProperty(value = "公司ID", required = true) + private Long companyId; + + /** 总金额 */ + @NotNull + @ApiModelProperty(value = "总金额", required = true) + private String amount; + + /** 状态描述 */ + @NotNull + @ApiModelProperty(value = "状态描述", required = true) + private String paymentResults; + + /** 店铺名称 */ + @NotNull + @ApiModelProperty(value = "店铺名称", required = true) + private String shop; + + /** 购买数量 */ + @NotNull + @ApiModelProperty(value = "购买数量", required = true) + private String pricesNumber; + + /** 订单id */ + @NotNull + @ApiModelProperty(value = "订单id", required = true) + private String orderId; + + /** 商品名称 */ + @NotNull + @ApiModelProperty(value = "商品名称", required = true) + private String shopName; + + /** 时间 */ + @NotNull + @ApiModelProperty(value = "时间", required = true) + private String orderDate; + + /** 评论 */ + @ApiModelProperty(value = "评论") + private String comment; + + /** 图片地址 */ + @ApiModelProperty(value = "图片地址") + private String paths; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickOrderCommentDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickOrderCommentDto.java new file mode 100644 index 0000000..19fb974 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickOrderCommentDto.java @@ -0,0 +1,34 @@ +package me.zhengjie.modules.group.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * 刷单-订单评论信息 + * + * @author rch + * @since 2022-10-20 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("新增评论") +public class CtClickOrderCommentDto { + /** 刷单订单id */ + @NotNull + @ApiModelProperty(value = "Id", required = true) + private Long id; + + /** 评论信息 */ + @ApiModelProperty(value = "评论信息") + private String comment; + + /** 图片地址 */ + @ApiModelProperty(value = "图片地址") + private String paths; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickOrderListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickOrderListDTO.java new file mode 100644 index 0000000..6751a07 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickOrderListDTO.java @@ -0,0 +1,69 @@ +package me.zhengjie.modules.group.dto; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.CtClickOrder; + + +/** + * @Description 分页查询 刷单订单信息 + * @Date 2022-06-22 + * @Author rch + */ +@Data +@ApiModel("分页查询刷单订单") +public class CtClickOrderListDTO extends PageDTO { + + /** 店铺 */ + @ApiModelProperty(value = "店铺") + private String shop; + + /** 订单id */ + @ApiModelProperty(value = "订单id") + private String orderId; + + /** 公司id */ + @ApiModelProperty(value = "公司id") + private Long companyId; + + /** 类型 */ + @ApiModelProperty(value = "类型") + private Integer type; + + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 */ + @ApiModelProperty(value = "状态 1.待执行 2.执行中 3.执行成功 4.执行失败", allowableValues = "1,2,3,4") + private Integer status; + + /** 开始时间 */ + @ApiModelProperty(value = "开始时间") + private String sTime; + + /** 结束时间 */ + @ApiModelProperty(value = "结束时间") + private String eTime; + + @ApiModelProperty(value = "是否评论") + private Boolean commentBoolean; + + public Wrapper getWrapper() { + QueryWrapper qw = new QueryWrapper(); + qw + .eq(ObjectUtil.isNotEmpty(companyId), "company.id", companyId) + .eq(ObjectUtil.isNotEmpty(status), "clickOrder.status", status) + .eq(ObjectUtil.isNotEmpty(type), "clickOrder.type", type) + .isNotNull((ObjectUtil.isNotEmpty(commentBoolean) && commentBoolean), "comment") + .like(ObjectUtil.isNotEmpty(shop), "clickOrder.shop", shop) + .like(ObjectUtil.isNotEmpty(orderId), "clickOrder.order_id", orderId) + .between(ObjectUtil.isNotEmpty(sTime) && ObjectUtil.isNotEmpty(eTime), "clickOrder.created_at", sTime, eTime) + .orderByDesc("created_at") + ; + + return qw; + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickOrderSupplementDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickOrderSupplementDto.java new file mode 100644 index 0000000..16043a3 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtClickOrderSupplementDto.java @@ -0,0 +1,58 @@ +package me.zhengjie.modules.group.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * 刷单-订单信息手动补录 + * + * @author rch + * @since 2022-10-15 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("补录订单信息") +public class CtClickOrderSupplementDto { + /** 刷单id */ + @NotNull + @ApiModelProperty(value = "刷单id", required = true) + private Long clickFarmingId; + + /** 总金额 */ + @NotNull + @ApiModelProperty(value = "总金额", required = true) + private String amount; + + /** 状态描述 */ + @NotNull + @ApiModelProperty(value = "状态描述", required = true) + private String paymentResults; + + /** 店铺名称 */ + @NotNull + @ApiModelProperty(value = "店铺名称", required = true) + private String shop; + + /** 购买数量 */ + @NotNull + @ApiModelProperty(value = "购买数量", required = true) + private String pricesNumber; + + /** 订单id */ + @ApiModelProperty(value = "订单id") + private String orderId; + + /** 商品名称 */ + @ApiModelProperty(value = "商品名称") + private String shopName; + + /** 时间 */ + @ApiModelProperty(value = "时间") + private String orderDate; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCompanyAddDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCompanyAddDTO.java new file mode 100644 index 0000000..dfad073 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCompanyAddDTO.java @@ -0,0 +1,29 @@ +package me.zhengjie.modules.group.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 公司信息 DTO + * + * @author rch + * @create 2022-06-28 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtCompanyAddDTO { + + /** 名称 */ + private String name; + /** 地址 */ + private String address; + /** 电话 */ + private String phone; + + // 下面这两个需要新增的时候生成 + /** 商户码(公司调用api公司唯一标识) */ + /** 商户token(公司调用api公司token身份标识) */ +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCompanyListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCompanyListDTO.java new file mode 100644 index 0000000..72aa00a --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCompanyListDTO.java @@ -0,0 +1,47 @@ +package me.zhengjie.modules.group.dto; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.Data; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.CtBuyer; + + +/** + * @Description 分页查询 公司信息 + * @Date 2022-06-28 + * @Author rch + */ +@Data +public class CtCompanyListDTO extends PageDTO { + /** 名称 */ + private String name; + /** 电话 */ + private String phone; + /** 地址 */ + private String address; + /** 商户码(公司调用api公司唯一标识) */ + private String number; + /** 商户token(公司调用api公司token身份标识) */ + private String token; + + /** 操作人账号*/ + private String gmName; + + public Wrapper getWrapper() { + QueryWrapper qw = new QueryWrapper(); + qw + .like(ObjectUtil.isNotEmpty(name), "name", name) + .like(ObjectUtil.isNotEmpty(phone), "phone", phone) + .like(ObjectUtil.isNotEmpty(address), "address", address) + .like(ObjectUtil.isNotEmpty(number), "number", number) + .like(ObjectUtil.isNotEmpty(token), "token", token) + .orderBy(ObjectUtil.isNotEmpty(getSort()), isAsc(), getSort()) + .orderByDesc("updated_at") + ; + + return qw; + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCompanyUpdateDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCompanyUpdateDTO.java new file mode 100644 index 0000000..0309484 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtCompanyUpdateDTO.java @@ -0,0 +1,30 @@ +package me.zhengjie.modules.group.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + + +/** + * 修改 买家 + * + * @author rch + * @create 2022-06-22 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtCompanyUpdateDTO { + + @NotNull + private Integer id; + /** 名称 */ + private String name; + /** 地址 */ + private String address; + /** 电话 */ + private String phone; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtDhPayAddDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtDhPayAddDTO.java new file mode 100644 index 0000000..22d3499 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtDhPayAddDTO.java @@ -0,0 +1,30 @@ +package me.zhengjie.modules.group.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; + +/** + * 敦煌支付信息 DTO + * + * @author rch + * @create 2022-07-09 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtDhPayAddDTO { + + /** 买家名称 */ + @NotBlank + private String buyerName; + + /** 支付订单ID(敦煌的) */ + @NotBlank + @Pattern(regexp = "^[0-9]+(,[0-9]+)*$", message = "订单编号不符合要求") + private String orderId; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtDhPayListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtDhPayListDTO.java new file mode 100644 index 0000000..3f3fa01 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtDhPayListDTO.java @@ -0,0 +1,39 @@ +package me.zhengjie.modules.group.dto; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.Data; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.CtBuyer; + + +/** + * @Description 分页查询 敦煌支付信息 + * @Date 2022-07-28 + * @Author rch + */ +@Data +public class CtDhPayListDTO extends PageDTO { + + /** 买家名称 */ + private String buyerName; + /** 支付订单ID(敦煌的) */ + private String orderId; + /** 状态 0.待处理 1.支付成功 2.支付失败 3.删除*/ + private Integer status; + + public Wrapper getWrapper() { + QueryWrapper qw = new QueryWrapper(); + qw + .eq(ObjectUtil.isNotEmpty(status), "status", status) + .like(ObjectUtil.isNotEmpty(buyerName), "buyer_name", buyerName) + .like(ObjectUtil.isNotEmpty(orderId), "order_id", orderId) + .orderBy(ObjectUtil.isNotEmpty(getSort()), isAsc(), getSort()) + .orderByDesc("updated_at") + ; + + return qw; + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtExcelAddDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtExcelAddDTO.java new file mode 100644 index 0000000..891b5f4 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtExcelAddDTO.java @@ -0,0 +1,27 @@ +package me.zhengjie.modules.group.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * Excel 导入信息(CtExcel)表实体类 DTO + * + * @author rch + * @since 2022-06-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtExcelAddDTO{ + + /** 备注 */ + @NotNull + private String remarks; + + /** excel路径 */ + @NotNull + private String path; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtExcelImportInfoListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtExcelImportInfoListDTO.java new file mode 100644 index 0000000..582100c --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtExcelImportInfoListDTO.java @@ -0,0 +1,41 @@ +package me.zhengjie.modules.group.dto; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.Data; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.CtBuyer; + + +/** + * @Description 分页查询 买家信息 + * @Date 2022-06-22 + * @Author rch + */ +@Data +public class CtExcelImportInfoListDTO extends PageDTO { + + /** 公司主键 */ + private Long companyId; + + /** 鉴权枚举 */ + private Integer tokenEnum; + + /** 状态 1.待处理 2.处理成功 3.处理失败 */ + private Integer status; + + public Wrapper getWrapper() { + QueryWrapper qw = new QueryWrapper(); + qw + .eq(ObjectUtil.isNotEmpty(companyId), "company_id", companyId) + .eq(ObjectUtil.isNotEmpty(tokenEnum), "token_enum", tokenEnum) + .eq(ObjectUtil.isNotEmpty(status), "status", status) + .orderBy(ObjectUtil.isNotEmpty(getSort()), isAsc(), getSort()) + .orderByDesc("updated_at") + ; + + return qw; + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtExcelListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtExcelListDTO.java new file mode 100644 index 0000000..e51b0f5 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtExcelListDTO.java @@ -0,0 +1,40 @@ +package me.zhengjie.modules.group.dto; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.CtExcel; + +/** + * Excel 导入信息(CtExcel)表实体类 DTO + * + * @author rch + * @since 2022-06-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtExcelListDTO extends PageDTO { + + /** 备注 */ + private String remarks; + + /** 状态1.待处理 2.已处理 */ + private Integer status; + + public Wrapper getWrapper() { + QueryWrapper qw = new QueryWrapper(); + qw + .like(ObjectUtil.isNotEmpty(remarks), "remarks", remarks) + .eq(ObjectUtil.isNotEmpty(status), "status", status) + .orderBy(ObjectUtil.isNotEmpty(getSort()), isAsc(), getSort()) + .orderByDesc("updated_at") + ; + + return qw; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtExcelUpdateDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtExcelUpdateDTO.java new file mode 100644 index 0000000..0dbd06b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtExcelUpdateDTO.java @@ -0,0 +1,27 @@ +package me.zhengjie.modules.group.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + + +/** + * 修改 Excel + * + * @author rch + * @create 2022-06-22 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtExcelUpdateDTO { + + @NotNull + private Integer id; + + /** 备注 */ + private String remarks; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtOrderListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtOrderListDTO.java new file mode 100644 index 0000000..75ce756 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtOrderListDTO.java @@ -0,0 +1,42 @@ +package me.zhengjie.modules.group.dto; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.Data; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.CtBuyer; + + +/** + * @Description 分页查询 订单信息 + * @Date 2022-07-01 + * @Author rch + */ +@Data +public class CtOrderListDTO extends PageDTO { + + /** 公司Id */ + private Long companyId; + /** ExcelId 信息 */ + private Long excelInfoId; + /** 我们平台订单编号 */ + private String ctOrderNo; + /** 订单号,下单成功响应的订单号(冗余字段 下单成功响应订单信息里有) */ + private Long orderNo; + + public Wrapper getWrapper() { + QueryWrapper qw = new QueryWrapper(); + qw + .eq(ObjectUtil.isNotEmpty(companyId), "company_id", companyId) + .eq(ObjectUtil.isNotEmpty(excelInfoId), "excel_info_id", excelInfoId) + .eq(ObjectUtil.isNotEmpty(ctOrderNo), "ct_order_no", ctOrderNo) + .eq(ObjectUtil.isNotEmpty(orderNo), "order_no", orderNo) + .orderBy(ObjectUtil.isNotEmpty(getSort()), isAsc(), getSort()) + .orderByDesc("updated_at") + ; + + return qw; + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtPlatformAddDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtPlatformAddDTO.java new file mode 100644 index 0000000..88a1c82 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtPlatformAddDTO.java @@ -0,0 +1,25 @@ +package me.zhengjie.modules.group.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 平台信息 DTO + * + * @author rch + * @create 2022-06-23 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtPlatformAddDTO { + + /** 名称 */ + private String name; + /** 地址 */ + private String address; + /** 电话 */ + private String phone; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtPlatformListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtPlatformListDTO.java new file mode 100644 index 0000000..a7d71a9 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtPlatformListDTO.java @@ -0,0 +1,39 @@ +package me.zhengjie.modules.group.dto; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.Data; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.CtPlatform; + + +/** + * @Description 分页查询 平台信息 + * @Date 2022-06-23 + * @Author rch + */ +@Data +public class CtPlatformListDTO extends PageDTO { + + /** 名称 */ + private String name; + /** 地址 */ + private String address; + /** 电话 */ + private String phone; + + public Wrapper getWrapper() { + QueryWrapper qw = new QueryWrapper(); + qw + .like(ObjectUtil.isNotEmpty(name), "name", name) + .like(ObjectUtil.isNotEmpty(address), "address", address) + .like(ObjectUtil.isNotEmpty(phone), "phone", phone) + .orderBy(ObjectUtil.isNotEmpty(getSort()), isAsc(), getSort()) + .orderByDesc("updated_at") + ; + + return qw; + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtPlatformUpdateDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtPlatformUpdateDTO.java new file mode 100644 index 0000000..e04fcd9 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtPlatformUpdateDTO.java @@ -0,0 +1,31 @@ +package me.zhengjie.modules.group.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + + +/** + * 修改 平台信息 + * + * @author rch + * @create 2022-06-22 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtPlatformUpdateDTO { + + @NotNull + private Integer id; + + /** 名称 */ + private String name; + /** 地址 */ + private String address; + /** 电话 */ + private String phone; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtRebotAddDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtRebotAddDTO.java new file mode 100644 index 0000000..0e58d38 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtRebotAddDTO.java @@ -0,0 +1,26 @@ +package me.zhengjie.modules.group.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * 影刀机器人(ct_rebot) 新增DTO + * + * @Author zhw + * @Date 2022-07-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtRebotAddDTO { + + /** 机器人账号 */ + @NotNull + private String accountName; + /** 机器人Uuid信息 */ + @NotNull + private String robotClientUuid; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtRebotListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtRebotListDTO.java new file mode 100644 index 0000000..3393a56 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtRebotListDTO.java @@ -0,0 +1,42 @@ +package me.zhengjie.modules.group.dto; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.CtRebot; + +/** + * 影刀机器人 分页查询DTO + * + * @Author zhw + * @Date 2022-07-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtRebotListDTO extends PageDTO { + + /** 机器人账号 */ + private String accountName; + /** 机器人Uuid信息 */ + private String robotClientUuid; + + public Wrapper getWrapper(){ + QueryWrapper qw = new QueryWrapper<>(); + qw + .like(ObjectUtil.isNotEmpty(accountName),"account_name",accountName) + .like(ObjectUtil.isNotEmpty(robotClientUuid),"robot_client_uuid",robotClientUuid) + .orderBy(ObjectUtil.isNotEmpty(getSort()),isAsc(),getSort()) + .orderByDesc("id") + ; + return qw; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtRebotUpdateDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtRebotUpdateDTO.java new file mode 100644 index 0000000..f5b9a4e --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtRebotUpdateDTO.java @@ -0,0 +1,33 @@ +package me.zhengjie.modules.group.dto; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * 根据ID修改影刀机器人(ct_rebot) 信息 + * + * @Author zhw + * @Date 2022-07-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtRebotUpdateDTO { + + @NotNull + private Long id; + + /** 机器人账号 */ + private String accountName; + /** 机器人Uuid信息 */ + private String robotClientUuid; + /** 任务id(任务id 不为0说明机器被占用) */ + private Integer jobId; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtRebotUpdateStatusDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtRebotUpdateStatusDTO.java new file mode 100644 index 0000000..fba3f4b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtRebotUpdateStatusDTO.java @@ -0,0 +1,24 @@ +package me.zhengjie.modules.group.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * 根据ID修改影刀机器人(ct_rebot) 状态测试使用 + * + * @Author zhw + * @Date 2022-07-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtRebotUpdateStatusDTO { + + @NotNull + private Long id; + + private Integer status; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtVpnAddDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtVpnAddDTO.java new file mode 100644 index 0000000..4c92a85 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtVpnAddDTO.java @@ -0,0 +1,50 @@ +package me.zhengjie.modules.group.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * @Author zhw + * @Date 2022-07-07 + * @Description Vpn新增DTO + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtVpnAddDTO { + /** 所属国家简称 */ + @NotNull + private String contntryShort; + /** IP地址 */ + @NotNull + private String ipAddress; + /** 父ip地址 */ + @NotNull + private String parentIpAddress; + /** 端口 */ + @NotNull + private Integer port; + /** 名称 */ + @NotNull + private String name; + /** 密码 */ + @NotNull + private String pwd; + /** VPS类型 1.传统 */ + @NotNull + private Integer vpsType; + /** 经销商 1.V2 */ + @NotNull + private Integer dealer; + /** mac地址 */ + @NotNull + public String mac; + /** 链接 */ + private String link; + /** 状态 1.可用 2.禁用 */ + public Integer status;; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtVpnListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtVpnListDTO.java new file mode 100644 index 0000000..06348ea --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtVpnListDTO.java @@ -0,0 +1,59 @@ +package me.zhengjie.modules.group.dto; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.Data; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.CtVpn; + +/** + * @Description 分页查询 VPN信息 + * @Date 2022/7/7 + * @Author zhw + */ +@Data +public class CtVpnListDTO extends PageDTO { + + /** 所属国家简称 */ + private String contntryShort; + /** IP地址 */ + private String ipAddress; + /** 父ip地址 */ + private String parentIpAddress; + /** 端口 */ + private Integer port; + /** 名称 */ + private String name; + /** 密码 */ + private String pwd; + /** VPS类型 1.传统 */ + private Integer vpsType; + /** 经销商 1.V2 */ + private Integer dealer; + /** mac地址 */ + public String mac; + /** 状态 1.可用 2.禁用 */ + public Integer status; + + public Wrapper getWrapper() { + QueryWrapper qw = new QueryWrapper(); + qw + .like(ObjectUtil.isNotEmpty(contntryShort), "contntry_short", contntryShort) + .like(ObjectUtil.isNotEmpty(ipAddress), "ip_address", ipAddress) + .like(ObjectUtil.isNotEmpty(parentIpAddress), "parent_ip_address", parentIpAddress) + .like(ObjectUtil.isNotEmpty(port), "port", port) + .like(ObjectUtil.isNotEmpty(name), "name", name) + .like(ObjectUtil.isNotEmpty(pwd), "pwd", pwd) + .like(ObjectUtil.isNotEmpty(vpsType), "vps_type", vpsType) + .like(ObjectUtil.isNotEmpty(dealer), "dealer", dealer) + .like(ObjectUtil.isNotEmpty(mac), "mac", mac) + .like(ObjectUtil.isNotEmpty(status), "status", status) + .orderBy(ObjectUtil.isNotEmpty(getSort()), isAsc(), getSort()) + .orderByDesc("updated_at") + ; + return qw; + } + + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtVpnUpdateDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtVpnUpdateDTO.java new file mode 100644 index 0000000..cfc9a4e --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/CtVpnUpdateDTO.java @@ -0,0 +1,43 @@ +package me.zhengjie.modules.group.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * @Author zhw + * @Date 2022-07-08 + * @Description VPN信息更新 dto + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CtVpnUpdateDTO { + @NotNull + private Integer id; + /** 所属国家简称 */ + private String contntryShort; + /** IP地址 */ + private String ipAddress; + /** 父ip地址 */ + private String parentIpAddress; + /** 端口 */ + private Integer port; + /** 名称 */ + private String name; + /** 密码 */ + private String pwd; + /** VPS类型 1.传统 */ + private Integer vpsType; + /** 经销商 1.V2 */ + private Integer dealer; + /** mac地址 */ + public String mac; + /** 链接 */ + private String link; + /** 经销商 1.可用 2.禁用 */ + public Integer status; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/DhCarGoodWellReceivedDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/DhCarGoodWellReceivedDTO.java new file mode 100644 index 0000000..0a7a804 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/DhCarGoodWellReceivedDTO.java @@ -0,0 +1,30 @@ +package me.zhengjie.modules.group.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * + * @Description IdDTO + * @Date 2022-06-22 + * @Author rch + */ +@Data +@ApiModel("敦煌加购好评商品细腻洗") +public class DhCarGoodWellReceivedDTO { + + @NotNull + @ApiModelProperty(value = "id", required = true) + private Long id; + + @NotNull + @ApiModelProperty(value = "评论内容", required = true) + private String comment; + + @NotNull + @ApiModelProperty(value = "图片路径", required = true) + private String paths; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/DhCarWellReceivedDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/DhCarWellReceivedDTO.java new file mode 100644 index 0000000..be59ac0 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/DhCarWellReceivedDTO.java @@ -0,0 +1,29 @@ +package me.zhengjie.modules.group.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * + * @Description IdDTO + * @Date 2022-06-22 + * @Author rch + */ +@Data +@ApiModel("敦煌加购好评") +public class DhCarWellReceivedDTO { + + @NotNull + @ApiModelProperty(value = "id", required = true) + private Long id; + + @Valid + @ApiModelProperty(value = "评论内容", required = true) + private List dialogWellReceivedGoods; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/IdDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/IdDTO.java new file mode 100644 index 0000000..8304628 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/IdDTO.java @@ -0,0 +1,22 @@ +package me.zhengjie.modules.group.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * + * @Description IdDTO + * @Date 2022-06-22 + * @Author rch + */ +@Data +@ApiModel("IdDto") +public class IdDTO { + + @NotNull + @ApiModelProperty(value = "id", required = true) + private Long id; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SearchOrderListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SearchOrderListDTO.java new file mode 100644 index 0000000..fab304d --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SearchOrderListDTO.java @@ -0,0 +1,69 @@ +package me.zhengjie.modules.group.dto; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.CtClickOrder; + + +/** + * @Description 分页查询 开放刷单订单接口给到ERP + * @Date 2022-11-10 + * @Author rch + */ +@Data +@ApiModel("分页查询刷单订单") +public class SearchOrderListDTO extends PageDTO { + + /** 店铺 */ + @ApiModelProperty(value = "店铺") + private String shop; + + /** 订单id */ + @ApiModelProperty(value = "订单id") + private String orderId; + + /** 公司id */ + @ApiModelProperty(value = "公司id") + private Long companyId; + + /** 类型 */ + @ApiModelProperty(value = "类型") + private Integer type; + + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 */ + @ApiModelProperty(value = "状态 1.待执行 2.执行中 3.执行成功 4.执行失败", allowableValues = "1,2,3,4") + private Integer status; + + /** 开始时间 */ + @ApiModelProperty(value = "开始时间") + private String sTime; + + /** 结束时间 */ + @ApiModelProperty(value = "结束时间") + private String eTime; + + @ApiModelProperty(value = "是否评论") + private Boolean commentBoolean; + + public Wrapper getWrapper() { + QueryWrapper qw = new QueryWrapper(); + qw + .eq(ObjectUtil.isNotEmpty(companyId), "company.id", companyId) + .eq(ObjectUtil.isNotEmpty(status), "clickOrder.status", status) + .eq(ObjectUtil.isNotEmpty(type), "clickOrder.type", type) + .isNotNull((ObjectUtil.isNotEmpty(commentBoolean) && commentBoolean), "comment") + .like(ObjectUtil.isNotEmpty(shop), "clickOrder.shop", shop) + .like(ObjectUtil.isNotEmpty(orderId), "clickOrder.order_id", orderId) + .between(ObjectUtil.isNotEmpty(sTime) && ObjectUtil.isNotEmpty(eTime), "clickOrder.created_at", sTime, eTime) + .orderByDesc("created_at") + ; + + return qw; + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SysQuartzJobAddDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SysQuartzJobAddDTO.java new file mode 100644 index 0000000..4c86419 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SysQuartzJobAddDTO.java @@ -0,0 +1,54 @@ +package me.zhengjie.modules.group.dto; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * @Description 影刀定时任务新增 DTO + * @Date 2022-07-21 + * @Author zhw + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SysQuartzJobAddDTO { + + private Long taskNum; + /** 任务名称 */ + @NotNull + private String jobName; + /** 备注 */ + @NotNull + private String description; + /** 应用id:根据应用查找bean名称和方法名称 */ + @NotNull + private Long applyId; + /** cron 表达式 */ + @NotNull + private String cronExpression; + /** 子任务ID */ + private String subTask; + /** 负责人 */ + @NotNull + private String personInCharge; + /** 报警邮箱 */ + private String email; + /** 失败后暂停:1暂停、0启用 */ + @NotNull + private Integer pauseAfterFailure; + /** 状态:1暂停、0启用 */ + @NotNull + private Integer isPause; + /** 参数 */ + @NotNull + private String params; + /** 参数类型 */ + @NotNull + private Integer paramsType; + + private String paramId; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SysQuartzJobListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SysQuartzJobListDTO.java new file mode 100644 index 0000000..fcb02fe --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SysQuartzJobListDTO.java @@ -0,0 +1,43 @@ +package me.zhengjie.modules.group.dto; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.Data; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.SysQuartzJob; +import me.zhengjie.enums.TaskTypeEnum; + +/** + * @Description 分页查询 影刀定时任务 + * @Date 2022-07-21 + * @Author zhw + */ +@Data +public class SysQuartzJobListDTO extends PageDTO { + + /** 任务名称 */ + private String jobName; + + /** 是否暂停 */ + private Integer isPause; + + /** 开始时间 */ + private String sTime; + + /** 结束时间 */ + private String eTime; + + public Wrapper getWrapper() { + QueryWrapper qw = new QueryWrapper<>(); + qw + .eq("type", TaskTypeEnum.SHADOW_KNIFE.value()) + .like(ObjectUtil.isNotEmpty(jobName), "job_name", jobName) + .eq(ObjectUtil.isNotEmpty(isPause), "is_pause", isPause) + .between(ObjectUtil.isNotEmpty(sTime) && ObjectUtil.isNotNull(eTime), "create_time", sTime, eTime) + .orderBy(ObjectUtil.isNotEmpty(getSort()), isAsc(), getSort()) + ; + return qw; + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SysQuartzJobUpdateDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SysQuartzJobUpdateDTO.java new file mode 100644 index 0000000..2c40feb --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SysQuartzJobUpdateDTO.java @@ -0,0 +1,49 @@ +package me.zhengjie.modules.group.dto; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + + +/** + * @Author zhw + * @Date 2022-07-21 + * @Description 影刀信息更新 dto + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SysQuartzJobUpdateDTO { + + @NotNull + private Long jobId; + /** 任务名称 */ + private String jobName; + /** 备注 */ + private String description; + /** Spring Bean名称 */ + private String beanName; + /** 方法名称 */ + private String methodName; + /** 应用ID 通过ID查找Bean名称、方法名称 */ + private Long applyId; + /** cron 表达式 */ + private String cronExpression; + /** 子任务ID */ + private String subTask; + /** 负责人 */ + private String personInCharge; + /** 报警邮箱 */ + private String email; + /** 失败后暂停:1暂停、0启用 */ + private Integer pauseAfterFailure; + /** 状态:1暂停、0启用 */ + private Integer isPause; + /** 参数 */ + private String params; + /** 参数类型 */ + private Integer paramsType; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SysQuartzLogListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SysQuartzLogListDTO.java new file mode 100644 index 0000000..7bb972d --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/SysQuartzLogListDTO.java @@ -0,0 +1,42 @@ +package me.zhengjie.modules.group.dto; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.Data; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.SysQuartzLog; +import me.zhengjie.enums.TaskTypeEnum; + + +/** + * @Description 分页查询 影刀定时任务日志 + * @Date 2022-07-9 + * @Author rch + */ +@Data +public class SysQuartzLogListDTO extends PageDTO { + + /** 卡号 */ + private String jobName; + + private Integer isSuccess; + + private String sTime; + + private String eTime; + + public Wrapper getWrapper() { + QueryWrapper qw = new QueryWrapper(); + qw + .eq("type", TaskTypeEnum.SHADOW_KNIFE.value()) + .eq(ObjectUtil.isNotEmpty(isSuccess), "is_success", isSuccess) + .like(ObjectUtil.isNotEmpty(jobName), "job_name", jobName) + .between(ObjectUtil.isNotEmpty(sTime) && ObjectUtil.isNotEmpty(eTime), "create_time", sTime, eTime) + .orderBy(ObjectUtil.isNotEmpty(getSort()), isAsc(), getSort()) + ; + + return qw; + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhaddcar/DhAddCarAddDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhaddcar/DhAddCarAddDTO.java new file mode 100644 index 0000000..098ca04 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhaddcar/DhAddCarAddDTO.java @@ -0,0 +1,46 @@ +package me.zhengjie.modules.group.dto.dhaddcar; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.modules.group.dto.dhcargood.DhCarGoodKeyAddDTO; +import me.zhengjie.modules.group.dto.dhcargood.DhCarGoodKeyEditDTO; +import me.zhengjie.modules.group.dto.dhcargood.DhCarGoodLinkAddDTO; +import me.zhengjie.modules.group.dto.dhcargood.DhCarGoodLinkEditDTO; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 新增敦煌加购 DTO + * + * @author rch + * @create 2022-07-09 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("新增敦煌加购") +public class DhAddCarAddDTO { + + /** 商品属性类型:1.关键词 2.链接 */ + @NotNull + @ApiModelProperty(value = "商品属性类型:1.关键词 2.链接", required = true, allowableValues = "1,2") + private Integer paramsType; + + /** 买家ID */ + @NotNull + @ApiModelProperty(value = "买家ID", required = true) + private Integer buyerId; + + /** 加购物车商品ids */ + @ApiModelProperty(value = "加购物车商品ids") + private List carGoodKeys; + + /** 加购物车商品ids */ + @ApiModelProperty(value = "加购物车商品ids") + private List carGoodLinks; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhaddcar/DhAddCarEditDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhaddcar/DhAddCarEditDTO.java new file mode 100644 index 0000000..b26d485 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhaddcar/DhAddCarEditDTO.java @@ -0,0 +1,48 @@ +package me.zhengjie.modules.group.dto.dhaddcar; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.modules.group.dto.dhcargood.DhCarGoodKeyEditDTO; +import me.zhengjie.modules.group.dto.dhcargood.DhCarGoodLinkEditDTO; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 修改敦煌加购信息 DTO + * + * @author rch + * @create 2022-07-09 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("修改敦煌加购信息") +public class DhAddCarEditDTO { + + /** ID */ + @ApiModelProperty(value = "ID", required = true) + private Long id; + + /** 商品属性类型:1.关键词 2.链接 */ + @NotNull + @ApiModelProperty(value = "商品属性类型:1.关键词 2.链接", required = true, allowableValues = "1,2") + private Integer paramsType; + + /** 买家ID */ + @NotNull + @ApiModelProperty(value = "买家ID", required = true) + private Integer buyerId; + + /** 加购物车商品ids */ + @ApiModelProperty(value = "加购物车商品ids") + private List carGoodKeys; + + /** 加购物车商品ids */ + @ApiModelProperty(value = "加购物车商品ids") + private List carGoodLinks; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhaddcar/DhAddCarListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhaddcar/DhAddCarListDTO.java new file mode 100644 index 0000000..e6a63c1 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhaddcar/DhAddCarListDTO.java @@ -0,0 +1,73 @@ +package me.zhengjie.modules.group.dto.dhaddcar; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.CtBuyer; +import me.zhengjie.enums.DhAddCarStatusEnum; + +import java.util.Arrays; + +/** + * 分页查询-敦煌加购-信息 DTO + * + * @author rch + * @create 2022-07-09 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("新增刷单信息") +public class DhAddCarListDTO extends PageDTO { + + /** 商品属性类型:1.关键词 2.链接 */ + @ApiModelProperty(value = "商品属性类型:1.关键词 2.链接", allowableValues = "1,2") + private Integer paramsType; + + /** 账号 */ + @ApiModelProperty(value = "账号") + private String account; + + /** 账号 */ + @ApiModelProperty(value = "国家") + private String country; + + /** 账号 */ + @ApiModelProperty(value = "1.获取敦煌加购列表(状态:1.待执行 4.加购失败); 2.获取敦煌抓单列表(状态:6.待抓单 9.抓单失败)") + private Integer inStatusList; + + /** 状态 1.待执行 2.执行中 3.加购成功 4.加购失败 5.下单成功 6.支付成功 7.抓单成功 8.抓单失败 */ + @ApiModelProperty(value = "状态 1.待执行 2.执行中 3.加购成功 4.加购失败 5.下单成功 6.支付成功 7.抓单成功 8.抓单失败", allowableValues = "1,2,3,4,5,6,7,8") + private Integer status; + +// /** 加购物车商品ids */ +// @ApiModelProperty(value = "加购物车商品ids") +// private List carGoodKeys; +// +// /** 加购物车商品ids */ +// @ApiModelProperty(value = "加购物车商品ids") +// private List carGoodLinks; + + public Wrapper getWrapper() { + QueryWrapper qw = new QueryWrapper(); + qw + .eq(ObjectUtil.isNotEmpty(paramsType), "dhAddCar.params_type", paramsType) + .eq(ObjectUtil.isNotEmpty(account), "buyer.account", account) + .in(ObjectUtil.isNotEmpty(inStatusList) && inStatusList == 1, "dhAddCar.status", Arrays.asList(DhAddCarStatusEnum.TOBE_EXECUTION.value(), DhAddCarStatusEnum.ADD_CARD_FAILE.value())) + .in(ObjectUtil.isNotEmpty(inStatusList) && inStatusList == 2, "dhAddCar.status", Arrays.asList(DhAddCarStatusEnum.TO_BE_CATCH_ORDER.value(), DhAddCarStatusEnum.CATCH_ORDER_FAILE.value())) + .eq(ObjectUtil.isNotEmpty(status), "dhAddCar.status", status) + .eq(ObjectUtil.isNotEmpty(country), "company.name", country) + .orderBy(ObjectUtil.isNotEmpty(getSort()), isAsc(), getSort()) + .orderByDesc("updated_at") + ; + + return qw; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcargood/DhCarGoodKeyAddDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcargood/DhCarGoodKeyAddDTO.java new file mode 100644 index 0000000..a4d8fb9 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcargood/DhCarGoodKeyAddDTO.java @@ -0,0 +1,70 @@ +package me.zhengjie.modules.group.dto.dhcargood; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Null; + +/** + * 敦煌-加购商品(根据关键词) DTO + * + * @author rch + * @create 2022-07-09 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("敦煌-加购商品(根据关键词)") +public class DhCarGoodKeyAddDTO { + + /** 商品属性类型:1.关键词 2.链接 */ + @Null + @ApiModelProperty(value = "商品属性类型:1.关键词 2.链接", required = true, allowableValues = "1,2") + private Integer paramsType; + + /** 店铺名称 */ + @NotBlank + @ApiModelProperty(value = "NotBlank", required = true) + private String shopName; + + /** 关键词 */ + @NotBlank + @ApiModelProperty(value = "关键词", required = true) + private String keyWord; + + /** 标题 */ + @NotBlank + @ApiModelProperty(value = "标题", required = true) + private String title; + + /** 数量 */ + @NotBlank + @ApiModelProperty(value = "数量", required = true) + private Integer number; + + /** 规格 */ + @ApiModelProperty(value = "规格") + private String specification; + + /** 颜色 */ + @ApiModelProperty(value = "颜色") + private String color; + + /** item */ + @NotBlank + @ApiModelProperty(value = "item", required = true) + private String item; + + /** 最小价格区间 */ + @ApiModelProperty(value = "最小价格区间") + private String sectionMin; + + /** 最大价格区间 */ + @ApiModelProperty(value = "最大价格区间") + private String sectionMax; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcargood/DhCarGoodKeyEditDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcargood/DhCarGoodKeyEditDTO.java new file mode 100644 index 0000000..3bdadc0 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcargood/DhCarGoodKeyEditDTO.java @@ -0,0 +1,74 @@ +package me.zhengjie.modules.group.dto.dhcargood; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Null; + +/** + * 敦煌-加购商品(根据关键词) DTO + * + * @author rch + * @create 2022-07-09 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("敦煌-加购商品(根据关键词)") +public class DhCarGoodKeyEditDTO { + + /** ID */ + @ApiModelProperty(value = "ID", required = true) + private Long id; + + /** 商品属性类型:1.关键词 2.链接 */ + @Null + @ApiModelProperty(value = "商品属性类型:1.关键词 2.链接", required = true, allowableValues = "1,2") + private Integer paramsType; + + /** 店铺名称 */ + @NotBlank + @ApiModelProperty(value = "NotBlank", required = true) + private String shopName; + + /** 关键词 */ + @NotBlank + @ApiModelProperty(value = "关键词", required = true) + private String keyWord; + + /** 标题 */ + @NotBlank + @ApiModelProperty(value = "标题", required = true) + private String title; + + /** 数量 */ + @NotBlank + @ApiModelProperty(value = "数量", required = true) + private Integer number; + + /** 规格 */ + @ApiModelProperty(value = "规格") + private String specification; + + /** 颜色 */ + @ApiModelProperty(value = "颜色") + private String color; + + /** item */ + @NotBlank + @ApiModelProperty(value = "item", required = true) + private String item; + + /** 最小价格区间 */ + @ApiModelProperty(value = "最小价格区间") + private String sectionMin; + + /** 最大价格区间 */ + @ApiModelProperty(value = "最大价格区间") + private String sectionMax; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcargood/DhCarGoodLinkAddDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcargood/DhCarGoodLinkAddDTO.java new file mode 100644 index 0000000..5911106 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcargood/DhCarGoodLinkAddDTO.java @@ -0,0 +1,49 @@ +package me.zhengjie.modules.group.dto.dhcargood; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Null; + +/** + * 敦煌-加购商品(根据链接) DTO + * + * @author rch + * @create 2022-07-09 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("敦煌-加购商品(根据链接)") +public class DhCarGoodLinkAddDTO { + + /** 商品属性类型:1.关键词 2.链接 */ + @Null + @ApiModelProperty(value = "商品属性类型:1.关键词 2.链接", required = true, allowableValues = "1,2") + private Integer paramsType; + + /** 链接 */ + @NotBlank + @ApiModelProperty(value = "链接", required = true) + private String link; + + /** 数量 */ + @NotBlank + @ApiModelProperty(value = "数量", required = true) + private Integer number; + + /** 规格 */ + @NotBlank + @ApiModelProperty(value = "规格", required = true) + private String specification; + + /** 颜色 */ + @NotBlank + @ApiModelProperty(value = "颜色", required = true) + private String color; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcargood/DhCarGoodLinkEditDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcargood/DhCarGoodLinkEditDTO.java new file mode 100644 index 0000000..e9c4a4a --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcargood/DhCarGoodLinkEditDTO.java @@ -0,0 +1,53 @@ +package me.zhengjie.modules.group.dto.dhcargood; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Null; + +/** + * 敦煌-加购商品(根据链接) DTO + * + * @author rch + * @create 2022-07-09 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("敦煌-加购商品(根据链接)") +public class DhCarGoodLinkEditDTO { + + /** ID */ + @ApiModelProperty(value = "ID", required = true) + private Long id; + + /** 商品属性类型:1.关键词 2.链接 */ + @Null + @ApiModelProperty(value = "商品属性类型:1.关键词 2.链接", required = true, allowableValues = "1,2") + private Integer paramsType; + + /** 链接 */ + @NotBlank + @ApiModelProperty(value = "链接", required = true) + private String link; + + /** 数量 */ + @NotBlank + @ApiModelProperty(value = "数量", required = true) + private Integer number; + + /** 规格 */ + @NotBlank + @ApiModelProperty(value = "规格", required = true) + private String specification; + + /** 颜色 */ + @NotBlank + @ApiModelProperty(value = "颜色", required = true) + private String color; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcarorder/DhAddCarOrderListDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcarorder/DhAddCarOrderListDTO.java new file mode 100644 index 0000000..e3ad0f3 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/group/dto/dhcarorder/DhAddCarOrderListDTO.java @@ -0,0 +1,66 @@ +package me.zhengjie.modules.group.dto.dhcarorder; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.dto.PageDTO; +import me.zhengjie.entity.CtBuyer; +import me.zhengjie.enums.ClickOrderStatusEnum; +import me.zhengjie.enums.DhAddCarStatusEnum; + +import java.util.Arrays; + +/** + * 分页查询-敦煌加购-订单-信息 DTO + * + * @author rch + * @create 2022-07-09 + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("敦煌加购订单信息") +public class DhAddCarOrderListDTO extends PageDTO { + + /** 类型: 1.导入 2.刷单 */ + @ApiModelProperty(value = "类型: 1.导入 2.刷单", allowableValues = "1,2") + private Integer type; + + /** 关联敦煌加购的id */ + @ApiModelProperty(value = "关联敦煌加购的id") + private Long addCarId; + + /** 订单id */ + @ApiModelProperty(value = "订单id") + private String orderId; + + /** 好评 */ + @ApiModelProperty(value = "1.获取敦煌好评列表(状态:1.待执行 4.加购失败)") + private Integer inStatusList; + + + /** 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 */ + @ApiModelProperty(value = "状态 1.待执行 2.执行中 3.执行成功 4.执行失败", allowableValues = "1,2,3,4") + private Integer status; + + public Wrapper getWrapper() { + QueryWrapper qw = new QueryWrapper(); + qw + .eq(ObjectUtil.isNotEmpty(type), "type", type) + .eq(ObjectUtil.isNotEmpty(addCarId), "add_car_id", addCarId) + .eq(ObjectUtil.isNotEmpty(orderId), "order_id", orderId) + .eq(ObjectUtil.isNotEmpty(status), "status", status) + .in(ObjectUtil.isNotEmpty(inStatusList) && inStatusList == 1, "status", Arrays.asList(ClickOrderStatusEnum.TOBE_EXECUTION.value(), ClickOrderStatusEnum.EXECUTION_FAILE.value())) + .orderBy(ObjectUtil.isNotEmpty(getSort()), isAsc(), getSort()) + .orderByDesc("updated_at") + ; + + return qw; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/App.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/App.java new file mode 100644 index 0000000..cf5789c --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/App.java @@ -0,0 +1,67 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.domain; + +import io.swagger.annotations.ApiModelProperty; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.copier.CopyOptions; +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseEntity; +import javax.persistence.*; +import java.io.Serializable; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Entity +@Getter +@Setter +@Table(name="mnt_app") +public class App extends BaseEntity implements Serializable { + + @Id + @Column(name = "app_id") + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ApiModelProperty(value = "名称") + private String name; + + @ApiModelProperty(value = "端口") + private int port; + + @ApiModelProperty(value = "上传路径") + private String uploadPath; + + @ApiModelProperty(value = "部署路径") + private String deployPath; + + @ApiModelProperty(value = "备份路径") + private String backupPath; + + @ApiModelProperty(value = "启动脚本") + private String startScript; + + @ApiModelProperty(value = "部署脚本") + private String deployScript; + + public void copy(App source){ + BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true)); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/Database.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/Database.java new file mode 100644 index 0000000..6b3a68a --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/Database.java @@ -0,0 +1,57 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.domain; + +import io.swagger.annotations.ApiModelProperty; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.copier.CopyOptions; +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseEntity; +import javax.persistence.*; +import java.io.Serializable; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Entity +@Getter +@Setter +@Table(name="mnt_database") +public class Database extends BaseEntity implements Serializable { + + @Id + @Column(name = "db_id") + @ApiModelProperty(value = "ID", hidden = true) + private String id; + + @ApiModelProperty(value = "数据库名称") + private String name; + + @ApiModelProperty(value = "数据库连接地址") + private String jdbcUrl; + + @ApiModelProperty(value = "数据库密码") + private String pwd; + + @ApiModelProperty(value = "用户名") + private String userName; + + public void copy(Database source){ + BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true)); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/Deploy.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/Deploy.java new file mode 100644 index 0000000..bcf61e5 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/Deploy.java @@ -0,0 +1,59 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.domain; + +import io.swagger.annotations.ApiModelProperty; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.copier.CopyOptions; +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseEntity; +import javax.persistence.*; +import java.io.Serializable; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Entity +@Getter +@Setter +@Table(name="mnt_deploy") +public class Deploy extends BaseEntity implements Serializable { + + @Id + @Column(name = "deploy_id") + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToMany + @ApiModelProperty(name = "服务器", hidden = true) + @JoinTable(name = "mnt_deploy_server", + joinColumns = {@JoinColumn(name = "deploy_id",referencedColumnName = "deploy_id")}, + inverseJoinColumns = {@JoinColumn(name = "server_id",referencedColumnName = "server_id")}) + private Set deploys; + + @ManyToOne + @JoinColumn(name = "app_id") + @ApiModelProperty(value = "应用编号") + private App app; + + public void copy(Deploy source){ + BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true)); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/DeployHistory.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/DeployHistory.java new file mode 100644 index 0000000..6e07e13 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/DeployHistory.java @@ -0,0 +1,62 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.domain; + +import io.swagger.annotations.ApiModelProperty; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.copier.CopyOptions; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.CreationTimestamp; +import javax.persistence.*; +import java.io.Serializable; +import java.sql.Timestamp; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Entity +@Getter +@Setter +@Table(name="mnt_deploy_history") +public class DeployHistory implements Serializable { + + @Id + @Column(name = "history_id") + @ApiModelProperty(value = "ID", hidden = true) + private String id; + + @ApiModelProperty(value = "应用名称") + private String appName; + + @ApiModelProperty(value = "IP") + private String ip; + + @CreationTimestamp + @ApiModelProperty(value = "部署时间") + private Timestamp deployDate; + + @ApiModelProperty(value = "部署者") + private String deployUser; + + @ApiModelProperty(value = "部署ID") + private Long deployId; + + public void copy(DeployHistory source){ + BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true)); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/ServerDeploy.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/ServerDeploy.java new file mode 100644 index 0000000..f523562 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/domain/ServerDeploy.java @@ -0,0 +1,80 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.domain; + +import io.swagger.annotations.ApiModelProperty; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.copier.CopyOptions; +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseEntity; +import javax.persistence.*; +import java.io.Serializable; +import java.util.Objects; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Entity +@Getter +@Setter +@Table(name="mnt_server") +public class ServerDeploy extends BaseEntity implements Serializable { + + @Id + @Column(name = "server_id") + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ApiModelProperty(value = "服务器名称") + private String name; + + @ApiModelProperty(value = "IP") + private String ip; + + @ApiModelProperty(value = "端口") + private Integer port; + + @ApiModelProperty(value = "账号") + private String account; + + @ApiModelProperty(value = "密码") + private String password; + + public void copy(ServerDeploy source){ + BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true)); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServerDeploy that = (ServerDeploy) o; + return Objects.equals(id, that.id) && + Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/AppRepository.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/AppRepository.java new file mode 100644 index 0000000..41e5f5c --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/AppRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.repository; + +import me.zhengjie.modules.mnt.domain.App; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +public interface AppRepository extends JpaRepository, JpaSpecificationExecutor { +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/DatabaseRepository.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/DatabaseRepository.java new file mode 100644 index 0000000..695e0ad --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/DatabaseRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.repository; + +import me.zhengjie.modules.mnt.domain.Database; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +public interface DatabaseRepository extends JpaRepository, JpaSpecificationExecutor { +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/DeployHistoryRepository.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/DeployHistoryRepository.java new file mode 100644 index 0000000..3c8980e --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/DeployHistoryRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.repository; + +import me.zhengjie.modules.mnt.domain.DeployHistory; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +public interface DeployHistoryRepository extends JpaRepository, JpaSpecificationExecutor { +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/DeployRepository.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/DeployRepository.java new file mode 100644 index 0000000..2ea4498 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/DeployRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.repository; + +import me.zhengjie.modules.mnt.domain.Deploy; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +public interface DeployRepository extends JpaRepository, JpaSpecificationExecutor { +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/ServerDeployRepository.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/ServerDeployRepository.java new file mode 100644 index 0000000..4ca336c --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/repository/ServerDeployRepository.java @@ -0,0 +1,34 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.repository; + +import me.zhengjie.modules.mnt.domain.ServerDeploy; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +public interface ServerDeployRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 根据IP查询 + * @param ip / + * @return / + */ + ServerDeploy findByIp(String ip); +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/AppController.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/AppController.java new file mode 100644 index 0000000..9b5b08f --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/AppController.java @@ -0,0 +1,87 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.Log; +import me.zhengjie.modules.mnt.domain.App; +import me.zhengjie.modules.mnt.service.AppService; +import me.zhengjie.modules.mnt.service.dto.AppQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@RestController +@RequiredArgsConstructor +@Api(tags = "运维:应用管理") +@RequestMapping("/api/app") +public class AppController { + + private final AppService appService; + + @ApiOperation("导出应用数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('app:list')") + public void download(HttpServletResponse response, AppQueryCriteria criteria) throws IOException { + appService.download(appService.queryAll(criteria), response); + } + + @ApiOperation(value = "查询应用") + @GetMapping + @PreAuthorize("@el.check('app:list')") + public ResponseEntity query(AppQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(appService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @Log("新增应用") + @ApiOperation(value = "新增应用") + @PostMapping + @PreAuthorize("@el.check('app:add')") + public ResponseEntity create(@Validated @RequestBody App resources){ + appService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改应用") + @ApiOperation(value = "修改应用") + @PutMapping + @PreAuthorize("@el.check('app:edit')") + public ResponseEntity update(@Validated @RequestBody App resources){ + appService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除应用") + @ApiOperation(value = "删除应用") + @DeleteMapping + @PreAuthorize("@el.check('app:del')") + public ResponseEntity delete(@RequestBody Set ids){ + appService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/DatabaseController.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/DatabaseController.java new file mode 100644 index 0000000..9dfb43c --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/DatabaseController.java @@ -0,0 +1,123 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.Log; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.mnt.domain.Database; +import me.zhengjie.modules.mnt.service.DatabaseService; +import me.zhengjie.modules.mnt.service.dto.DatabaseDto; +import me.zhengjie.modules.mnt.service.dto.DatabaseQueryCriteria; +import me.zhengjie.modules.mnt.util.SqlUtils; +import me.zhengjie.utils.FileUtil; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Api(tags = "运维:数据库管理") +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/database") +public class DatabaseController { + + private final String fileSavePath = FileUtil.getTmpDirPath()+"/"; + private final DatabaseService databaseService; + + @ApiOperation("导出数据库数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('database:list')") + public void download(HttpServletResponse response, DatabaseQueryCriteria criteria) throws IOException { + databaseService.download(databaseService.queryAll(criteria), response); + } + + @ApiOperation(value = "查询数据库") + @GetMapping + @PreAuthorize("@el.check('database:list')") + public ResponseEntity query(DatabaseQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(databaseService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @Log("新增数据库") + @ApiOperation(value = "新增数据库") + @PostMapping + @PreAuthorize("@el.check('database:add')") + public ResponseEntity create(@Validated @RequestBody Database resources){ + databaseService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改数据库") + @ApiOperation(value = "修改数据库") + @PutMapping + @PreAuthorize("@el.check('database:edit')") + public ResponseEntity update(@Validated @RequestBody Database resources){ + databaseService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除数据库") + @ApiOperation(value = "删除数据库") + @DeleteMapping + @PreAuthorize("@el.check('database:del')") + public ResponseEntity delete(@RequestBody Set ids){ + databaseService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + @Log("测试数据库链接") + @ApiOperation(value = "测试数据库链接") + @PostMapping("/testConnect") + @PreAuthorize("@el.check('database:testConnect')") + public ResponseEntity testConnect(@Validated @RequestBody Database resources){ + return new ResponseEntity<>(databaseService.testConnection(resources),HttpStatus.CREATED); + } + + @Log("执行SQL脚本") + @ApiOperation(value = "执行SQL脚本") + @PostMapping(value = "/upload") + @PreAuthorize("@el.check('database:add')") + public ResponseEntity upload(@RequestBody MultipartFile file, HttpServletRequest request)throws Exception{ + String id = request.getParameter("id"); + DatabaseDto database = databaseService.findById(id); + String fileName; + if(database != null){ + fileName = file.getOriginalFilename(); + File executeFile = new File(fileSavePath+fileName); + FileUtil.del(executeFile); + file.transferTo(executeFile); + String result = SqlUtils.executeFile(database.getJdbcUrl(), database.getUserName(), database.getPwd(), executeFile); + return new ResponseEntity<>(result,HttpStatus.OK); + }else{ + throw new BadRequestException("Database not exist"); + } + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/DeployController.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/DeployController.java new file mode 100644 index 0000000..72b7b3e --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/DeployController.java @@ -0,0 +1,153 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.Log; +import me.zhengjie.modules.mnt.domain.Deploy; +import me.zhengjie.modules.mnt.domain.DeployHistory; +import me.zhengjie.modules.mnt.service.DeployService; +import me.zhengjie.modules.mnt.service.dto.DeployQueryCriteria; +import me.zhengjie.utils.FileUtil; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@RestController +@Api(tags = "运维:部署管理") +@RequiredArgsConstructor +@RequestMapping("/api/deploy") +public class DeployController { + + private final String fileSavePath = FileUtil.getTmpDirPath()+"/"; + private final DeployService deployService; + + + @ApiOperation("导出部署数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('database:list')") + public void download(HttpServletResponse response, DeployQueryCriteria criteria) throws IOException { + deployService.download(deployService.queryAll(criteria), response); + } + + @ApiOperation(value = "查询部署") + @GetMapping + @PreAuthorize("@el.check('deploy:list')") + public ResponseEntity query(DeployQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(deployService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @Log("新增部署") + @ApiOperation(value = "新增部署") + @PostMapping + @PreAuthorize("@el.check('deploy:add')") + public ResponseEntity create(@Validated @RequestBody Deploy resources){ + deployService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改部署") + @ApiOperation(value = "修改部署") + @PutMapping + @PreAuthorize("@el.check('deploy:edit')") + public ResponseEntity update(@Validated @RequestBody Deploy resources){ + deployService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除部署") + @ApiOperation(value = "删除部署") + @DeleteMapping + @PreAuthorize("@el.check('deploy:del')") + public ResponseEntity delete(@RequestBody Set ids){ + deployService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + @Log("上传文件部署") + @ApiOperation(value = "上传文件部署") + @PostMapping(value = "/upload") + @PreAuthorize("@el.check('deploy:edit')") + public ResponseEntity upload(@RequestBody MultipartFile file, HttpServletRequest request)throws Exception{ + Long id = Long.valueOf(request.getParameter("id")); + String fileName = ""; + if(file != null){ + fileName = file.getOriginalFilename(); + File deployFile = new File(fileSavePath+fileName); + FileUtil.del(deployFile); + file.transferTo(deployFile); + //文件下一步要根据文件名字来 + deployService.deploy(fileSavePath+fileName ,id); + }else{ + System.out.println("没有找到相对应的文件"); + } + System.out.println("文件上传的原名称为:"+ Objects.requireNonNull(file).getOriginalFilename()); + Map map = new HashMap<>(2); + map.put("errno",0); + map.put("id",fileName); + return new ResponseEntity<>(map,HttpStatus.OK); + } + @Log("系统还原") + @ApiOperation(value = "系统还原") + @PostMapping(value = "/serverReduction") + @PreAuthorize("@el.check('deploy:edit')") + public ResponseEntity serverReduction(@Validated @RequestBody DeployHistory resources){ + String result = deployService.serverReduction(resources); + return new ResponseEntity<>(result,HttpStatus.OK); + } + @Log("服务运行状态") + @ApiOperation(value = "服务运行状态") + @PostMapping(value = "/serverStatus") + @PreAuthorize("@el.check('deploy:edit')") + public ResponseEntity serverStatus(@Validated @RequestBody Deploy resources){ + String result = deployService.serverStatus(resources); + return new ResponseEntity<>(result,HttpStatus.OK); + } + @Log("启动服务") + @ApiOperation(value = "启动服务") + @PostMapping(value = "/startServer") + @PreAuthorize("@el.check('deploy:edit')") + public ResponseEntity startServer(@Validated @RequestBody Deploy resources){ + String result = deployService.startServer(resources); + return new ResponseEntity<>(result,HttpStatus.OK); + } + @Log("停止服务") + @ApiOperation(value = "停止服务") + @PostMapping(value = "/stopServer") + @PreAuthorize("@el.check('deploy:edit')") + public ResponseEntity stopServer(@Validated @RequestBody Deploy resources){ + String result = deployService.stopServer(resources); + return new ResponseEntity<>(result,HttpStatus.OK); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/DeployHistoryController.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/DeployHistoryController.java new file mode 100644 index 0000000..49fb694 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/DeployHistoryController.java @@ -0,0 +1,67 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.Log; +import me.zhengjie.modules.mnt.service.DeployHistoryService; +import me.zhengjie.modules.mnt.service.dto.DeployHistoryQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@RestController +@RequiredArgsConstructor +@Api(tags = "运维:部署历史管理") +@RequestMapping("/api/deployHistory") +public class DeployHistoryController { + + private final DeployHistoryService deployhistoryService; + + @ApiOperation("导出部署历史数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('deployHistory:list')") + public void download(HttpServletResponse response, DeployHistoryQueryCriteria criteria) throws IOException { + deployhistoryService.download(deployhistoryService.queryAll(criteria), response); + } + + @ApiOperation(value = "查询部署历史") + @GetMapping + @PreAuthorize("@el.check('deployHistory:list')") + public ResponseEntity query(DeployHistoryQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(deployhistoryService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @Log("删除DeployHistory") + @ApiOperation(value = "删除部署历史") + @DeleteMapping + @PreAuthorize("@el.check('deployHistory:del')") + public ResponseEntity delete(@RequestBody Set ids){ + deployhistoryService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/ServerDeployController.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/ServerDeployController.java new file mode 100644 index 0000000..d4a135b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/rest/ServerDeployController.java @@ -0,0 +1,95 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.Log; +import me.zhengjie.modules.mnt.domain.ServerDeploy; +import me.zhengjie.modules.mnt.service.ServerDeployService; +import me.zhengjie.modules.mnt.service.dto.ServerDeployQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@RestController +@Api(tags = "运维:服务器管理") +@RequiredArgsConstructor +@RequestMapping("/api/serverDeploy") +public class ServerDeployController { + + private final ServerDeployService serverDeployService; + + @ApiOperation("导出服务器数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('serverDeploy:list')") + public void download(HttpServletResponse response, ServerDeployQueryCriteria criteria) throws IOException { + serverDeployService.download(serverDeployService.queryAll(criteria), response); + } + + @ApiOperation(value = "查询服务器") + @GetMapping + @PreAuthorize("@el.check('serverDeploy:list')") + public ResponseEntity query(ServerDeployQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(serverDeployService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @Log("新增服务器") + @ApiOperation(value = "新增服务器") + @PostMapping + @PreAuthorize("@el.check('serverDeploy:add')") + public ResponseEntity create(@Validated @RequestBody ServerDeploy resources){ + serverDeployService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改服务器") + @ApiOperation(value = "修改服务器") + @PutMapping + @PreAuthorize("@el.check('serverDeploy:edit')") + public ResponseEntity update(@Validated @RequestBody ServerDeploy resources){ + serverDeployService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除服务器") + @ApiOperation(value = "删除Server") + @DeleteMapping + @PreAuthorize("@el.check('serverDeploy:del')") + public ResponseEntity delete(@RequestBody Set ids){ + serverDeployService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + @Log("测试连接服务器") + @ApiOperation(value = "测试连接服务器") + @PostMapping("/testConnect") + @PreAuthorize("@el.check('serverDeploy:add')") + public ResponseEntity testConnect(@Validated @RequestBody ServerDeploy resources){ + return new ResponseEntity<>(serverDeployService.testConnect(resources),HttpStatus.CREATED); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/AppService.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/AppService.java new file mode 100644 index 0000000..c822778 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/AppService.java @@ -0,0 +1,81 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service; + +import me.zhengjie.modules.mnt.domain.App; +import me.zhengjie.modules.mnt.service.dto.AppDto; +import me.zhengjie.modules.mnt.service.dto.AppQueryCriteria; +import org.springframework.data.domain.Pageable; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +public interface AppService { + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(AppQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部数据 + * @param criteria 条件 + * @return / + */ + List queryAll(AppQueryCriteria criteria); + + /** + * 根据ID查询 + * @param id / + * @return / + */ + AppDto findById(Long id); + + /** + * 创建 + * @param resources / + */ + void create(App resources); + + /** + * 编辑 + * @param resources / + */ + void update(App resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 导出数据 + * @param queryAll / + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/DatabaseService.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/DatabaseService.java new file mode 100644 index 0000000..e8a3acb --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/DatabaseService.java @@ -0,0 +1,88 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service; + +import me.zhengjie.modules.mnt.domain.Database; +import me.zhengjie.modules.mnt.service.dto.DatabaseDto; +import me.zhengjie.modules.mnt.service.dto.DatabaseQueryCriteria; +import org.springframework.data.domain.Pageable; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** + * @author ZhangHouYing + * @date 2019-08-24 + */ +public interface DatabaseService { + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(DatabaseQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部 + * @param criteria 条件 + * @return / + */ + List queryAll(DatabaseQueryCriteria criteria); + + /** + * 根据ID查询 + * @param id / + * @return / + */ + DatabaseDto findById(String id); + + /** + * 创建 + * @param resources / + */ + void create(Database resources); + + /** + * 编辑 + * @param resources / + */ + void update(Database resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 测试连接数据库 + * @param resources / + * @return / + */ + boolean testConnection(Database resources); + + /** + * 导出数据 + * @param queryAll / + * @param response / + * @throws IOException e + */ + void download(List queryAll, HttpServletResponse response) throws IOException; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/DeployHistoryService.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/DeployHistoryService.java new file mode 100644 index 0000000..5eb1b3d --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/DeployHistoryService.java @@ -0,0 +1,74 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service; + +import me.zhengjie.modules.mnt.domain.DeployHistory; +import me.zhengjie.modules.mnt.service.dto.DeployHistoryDto; +import me.zhengjie.modules.mnt.service.dto.DeployHistoryQueryCriteria; +import org.springframework.data.domain.Pageable; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** + * @author zhanghouying + */ +public interface DeployHistoryService { + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(DeployHistoryQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部 + * @param criteria 条件 + * @return / + */ + List queryAll(DeployHistoryQueryCriteria criteria); + + /** + * 根据ID查询 + * @param id / + * @return / + */ + DeployHistoryDto findById(String id); + + /** + * 创建 + * @param resources / + */ + void create(DeployHistory resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 导出数据 + * @param queryAll / + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/DeployService.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/DeployService.java new file mode 100644 index 0000000..583474d --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/DeployService.java @@ -0,0 +1,116 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service; + +import me.zhengjie.modules.mnt.domain.Deploy; +import me.zhengjie.modules.mnt.domain.DeployHistory; +import me.zhengjie.modules.mnt.service.dto.DeployDto; +import me.zhengjie.modules.mnt.service.dto.DeployQueryCriteria; +import org.springframework.data.domain.Pageable; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +public interface DeployService { + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(DeployQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部数据 + * @param criteria 条件 + * @return / + */ + List queryAll(DeployQueryCriteria criteria); + + /** + * 根据ID查询 + * @param id / + * @return / + */ + DeployDto findById(Long id); + + /** + * 创建 + * @param resources / + */ + void create(Deploy resources); + + + /** + * 编辑 + * @param resources / + */ + void update(Deploy resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 部署文件到服务器 + * @param fileSavePath 文件路径 + * @param appId 应用ID + */ + void deploy(String fileSavePath, Long appId); + + /** + * 查询部署状态 + * @param resources / + * @return / + */ + String serverStatus(Deploy resources); + /** + * 启动服务 + * @param resources / + * @return / + */ + String startServer(Deploy resources); + /** + * 停止服务 + * @param resources / + * @return / + */ + String stopServer(Deploy resources); + + /** + * 停止服务 + * @param resources / + * @return / + */ + String serverReduction(DeployHistory resources); + + /** + * 导出数据 + * @param queryAll / + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/ServerDeployService.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/ServerDeployService.java new file mode 100644 index 0000000..be8bb57 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/ServerDeployService.java @@ -0,0 +1,95 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service; + +import me.zhengjie.modules.mnt.domain.ServerDeploy; +import me.zhengjie.modules.mnt.service.dto.ServerDeployDto; +import me.zhengjie.modules.mnt.service.dto.ServerDeployQueryCriteria; +import org.springframework.data.domain.Pageable; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +public interface ServerDeployService { + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(ServerDeployQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部数据 + * @param criteria 条件 + * @return / + */ + List queryAll(ServerDeployQueryCriteria criteria); + + /** + * 根据ID查询 + * @param id / + * @return / + */ + ServerDeployDto findById(Long id); + + /** + * 创建 + * @param resources / + */ + void create(ServerDeploy resources); + + /** + * 编辑 + * @param resources / + */ + void update(ServerDeploy resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 根据IP查询 + * @param ip / + * @return / + */ + ServerDeployDto findByIp(String ip); + + /** + * 测试登录服务器 + * @param resources / + * @return / + */ + Boolean testConnect(ServerDeploy resources); + + /** + * 导出数据 + * @param queryAll / + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/AppDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/AppDto.java new file mode 100644 index 0000000..c6fd6f7 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/AppDto.java @@ -0,0 +1,71 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.dto; + +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseDTO; +import java.io.Serializable; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Getter +@Setter +public class AppDto extends BaseDTO implements Serializable { + + /** + * 应用编号 + */ + private Long id; + + /** + * 应用名称 + */ + private String name; + + /** + * 端口 + */ + private Integer port; + + /** + * 上传目录 + */ + private String uploadPath; + + /** + * 部署目录 + */ + private String deployPath; + + /** + * 备份目录 + */ + private String backupPath; + + /** + * 启动脚本 + */ + private String startScript; + + /** + * 部署脚本 + */ + private String deployScript; + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/AppQueryCriteria.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/AppQueryCriteria.java new file mode 100644 index 0000000..17f358f --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/AppQueryCriteria.java @@ -0,0 +1,38 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.dto; + +import lombok.Data; +import me.zhengjie.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Data +public class AppQueryCriteria{ + + /** + * 模糊 + */ + @Query(type = Query.Type.INNER_LIKE) + private String name; + + @Query(type = Query.Type.BETWEEN) + private List createTime; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DatabaseDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DatabaseDto.java new file mode 100644 index 0000000..689b06b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DatabaseDto.java @@ -0,0 +1,55 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.dto; + +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseDTO; +import java.io.Serializable; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Getter +@Setter +public class DatabaseDto extends BaseDTO implements Serializable { + + /** + * id + */ + private String id; + + /** + * 数据库名称 + */ + private String name; + + /** + * 数据库连接地址 + */ + private String jdbcUrl; + + /** + * 数据库密码 + */ + private String pwd; + + /** + * 用户名 + */ + private String userName; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DatabaseQueryCriteria.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DatabaseQueryCriteria.java new file mode 100644 index 0000000..53d619d --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DatabaseQueryCriteria.java @@ -0,0 +1,44 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.dto; + +import lombok.Data; +import me.zhengjie.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Data +public class DatabaseQueryCriteria{ + + /** + * 模糊 + */ + @Query(type = Query.Type.INNER_LIKE) + private String name; + + /** + * 精确 + */ + @Query + private String jdbcUrl; + + @Query(type = Query.Type.BETWEEN) + private List createTime; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DeployDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DeployDto.java new file mode 100644 index 0000000..f3d77b8 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DeployDto.java @@ -0,0 +1,78 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.dto; + +import cn.hutool.core.collection.CollectionUtil; +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseDTO; +import java.io.Serializable; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Getter +@Setter +public class DeployDto extends BaseDTO implements Serializable { + + /** + * 部署编号 + */ + private String id; + + private AppDto app; + + /** + * 服务器 + */ + private Set deploys; + + private String servers; + + /** + * 服务状态 + */ + private String status; + + public String getServers() { + if(CollectionUtil.isNotEmpty(deploys)){ + return deploys.stream().map(ServerDeployDto::getName).collect(Collectors.joining(",")); + } + return servers; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DeployDto deployDto = (DeployDto) o; + return Objects.equals(id, deployDto.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DeployHistoryDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DeployHistoryDto.java new file mode 100644 index 0000000..a9f480c --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DeployHistoryDto.java @@ -0,0 +1,58 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.dto; + +import lombok.Data; +import java.io.Serializable; +import java.sql.Timestamp; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Data +public class DeployHistoryDto implements Serializable { + + /** + * 编号 + */ + private String id; + + /** + * 应用名称 + */ + private String appName; + + /** + * 部署IP + */ + private String ip; + + /** + * 部署时间 + */ + private Timestamp deployDate; + + /** + * 部署人员 + */ + private String deployUser; + + /** + * 部署编号 + */ + private Long deployId; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DeployHistoryQueryCriteria.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DeployHistoryQueryCriteria.java new file mode 100644 index 0000000..c34f124 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DeployHistoryQueryCriteria.java @@ -0,0 +1,41 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.dto; + +import lombok.Data; +import me.zhengjie.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Data +public class DeployHistoryQueryCriteria{ + + /** + * 精确 + */ + @Query(blurry = "appName,ip,deployUser") + private String blurry; + + @Query + private Long deployId; + + @Query(type = Query.Type.BETWEEN) + private List deployDate; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DeployQueryCriteria.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DeployQueryCriteria.java new file mode 100644 index 0000000..c404620 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/DeployQueryCriteria.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.dto; + +import lombok.Data; +import me.zhengjie.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Data +public class DeployQueryCriteria{ + + /** + * 模糊 + */ + @Query(type = Query.Type.INNER_LIKE, propName = "name", joinName = "app") + private String appName; + + @Query(type = Query.Type.BETWEEN) + private List createTime; + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/ServerDeployDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/ServerDeployDto.java new file mode 100644 index 0000000..a49c795 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/ServerDeployDto.java @@ -0,0 +1,61 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.dto; + +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseDTO; +import java.io.Serializable; +import java.util.Objects; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Getter +@Setter +public class ServerDeployDto extends BaseDTO implements Serializable { + + private Long id; + + private String name; + + private String ip; + + private Integer port; + + private String account; + + private String password; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServerDeployDto that = (ServerDeployDto) o; + return Objects.equals(id, that.id) && + Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/ServerDeployQueryCriteria.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/ServerDeployQueryCriteria.java new file mode 100644 index 0000000..bb8bd41 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/dto/ServerDeployQueryCriteria.java @@ -0,0 +1,38 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.dto; + +import lombok.Data; +import me.zhengjie.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Data +public class ServerDeployQueryCriteria{ + + /** + * 模糊 + */ + @Query(blurry = "name,ip,account") + private String blurry; + + @Query(type = Query.Type.BETWEEN) + private List createTime; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/AppServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/AppServiceImpl.java new file mode 100644 index 0000000..42b088f --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/AppServiceImpl.java @@ -0,0 +1,123 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.impl; + +import lombok.RequiredArgsConstructor; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.mnt.domain.App; +import me.zhengjie.modules.mnt.repository.AppRepository; +import me.zhengjie.modules.mnt.service.AppService; +import me.zhengjie.modules.mnt.service.dto.AppDto; +import me.zhengjie.modules.mnt.service.dto.AppQueryCriteria; +import me.zhengjie.modules.mnt.service.mapstruct.AppMapper; +import me.zhengjie.utils.FileUtil; +import me.zhengjie.utils.PageUtil; +import me.zhengjie.utils.QueryHelp; +import me.zhengjie.utils.ValidationUtil; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Service +@RequiredArgsConstructor +public class AppServiceImpl implements AppService { + + private final AppRepository appRepository; + private final AppMapper appMapper; + + @Override + public Object queryAll(AppQueryCriteria criteria, Pageable pageable){ + Page page = appRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); + return PageUtil.toPage(page.map(appMapper::toDto)); + } + + @Override + public List queryAll(AppQueryCriteria criteria){ + return appMapper.toDto(appRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder))); + } + + @Override + public AppDto findById(Long id) { + App app = appRepository.findById(id).orElseGet(App::new); + ValidationUtil.isNull(app.getId(),"App","id",id); + return appMapper.toDto(app); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(App resources) { + verification(resources); + appRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(App resources) { + verification(resources); + App app = appRepository.findById(resources.getId()).orElseGet(App::new); + ValidationUtil.isNull(app.getId(),"App","id",resources.getId()); + app.copy(resources); + appRepository.save(app); + } + + private void verification(App resources){ + String opt = "/opt"; + String home = "/home"; + if (!(resources.getUploadPath().startsWith(opt) || resources.getUploadPath().startsWith(home))) { + throw new BadRequestException("文件只能上传在opt目录或者home目录 "); + } + if (!(resources.getDeployPath().startsWith(opt) || resources.getDeployPath().startsWith(home))) { + throw new BadRequestException("文件只能部署在opt目录或者home目录 "); + } + if (!(resources.getBackupPath().startsWith(opt) || resources.getBackupPath().startsWith(home))) { + throw new BadRequestException("文件只能备份在opt目录或者home目录 "); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + for (Long id : ids) { + appRepository.deleteById(id); + } + } + + @Override + public void download(List queryAll, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (AppDto appDto : queryAll) { + Map map = new LinkedHashMap<>(); + map.put("应用名称", appDto.getName()); + map.put("端口", appDto.getPort()); + map.put("上传目录", appDto.getUploadPath()); + map.put("部署目录", appDto.getDeployPath()); + map.put("备份目录", appDto.getBackupPath()); + map.put("启动脚本", appDto.getStartScript()); + map.put("部署脚本", appDto.getDeployScript()); + map.put("创建日期", appDto.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/DatabaseServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/DatabaseServiceImpl.java new file mode 100644 index 0000000..c774028 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/DatabaseServiceImpl.java @@ -0,0 +1,117 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.impl; + +import cn.hutool.core.util.IdUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.modules.mnt.domain.Database; +import me.zhengjie.modules.mnt.repository.DatabaseRepository; +import me.zhengjie.modules.mnt.service.DatabaseService; +import me.zhengjie.modules.mnt.service.dto.DatabaseDto; +import me.zhengjie.modules.mnt.service.dto.DatabaseQueryCriteria; +import me.zhengjie.modules.mnt.service.mapstruct.DatabaseMapper; +import me.zhengjie.modules.mnt.util.SqlUtils; +import me.zhengjie.utils.FileUtil; +import me.zhengjie.utils.PageUtil; +import me.zhengjie.utils.QueryHelp; +import me.zhengjie.utils.ValidationUtil; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Slf4j +@Service +@RequiredArgsConstructor +public class DatabaseServiceImpl implements DatabaseService { + + private final DatabaseRepository databaseRepository; + private final DatabaseMapper databaseMapper; + + @Override + public Object queryAll(DatabaseQueryCriteria criteria, Pageable pageable){ + Page page = databaseRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); + return PageUtil.toPage(page.map(databaseMapper::toDto)); + } + + @Override + public List queryAll(DatabaseQueryCriteria criteria){ + return databaseMapper.toDto(databaseRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder))); + } + + @Override + public DatabaseDto findById(String id) { + Database database = databaseRepository.findById(id).orElseGet(Database::new); + ValidationUtil.isNull(database.getId(),"Database","id",id); + return databaseMapper.toDto(database); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Database resources) { + resources.setId(IdUtil.simpleUUID()); + databaseRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(Database resources) { + Database database = databaseRepository.findById(resources.getId()).orElseGet(Database::new); + ValidationUtil.isNull(database.getId(),"Database","id",resources.getId()); + database.copy(resources); + databaseRepository.save(database); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + for (String id : ids) { + databaseRepository.deleteById(id); + } + } + + @Override + public boolean testConnection(Database resources) { + try { + return SqlUtils.testConnection(resources.getJdbcUrl(), resources.getUserName(), resources.getPwd()); + } catch (Exception e) { + log.error(e.getMessage()); + return false; + } + } + + @Override + public void download(List queryAll, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (DatabaseDto databaseDto : queryAll) { + Map map = new LinkedHashMap<>(); + map.put("数据库名称", databaseDto.getName()); + map.put("数据库连接地址", databaseDto.getJdbcUrl()); + map.put("用户名", databaseDto.getUserName()); + map.put("创建日期", databaseDto.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/DeployHistoryServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/DeployHistoryServiceImpl.java new file mode 100644 index 0000000..7431113 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/DeployHistoryServiceImpl.java @@ -0,0 +1,96 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.impl; + +import cn.hutool.core.util.IdUtil; +import lombok.RequiredArgsConstructor; +import me.zhengjie.modules.mnt.domain.DeployHistory; +import me.zhengjie.modules.mnt.repository.DeployHistoryRepository; +import me.zhengjie.modules.mnt.service.DeployHistoryService; +import me.zhengjie.modules.mnt.service.dto.DeployHistoryDto; +import me.zhengjie.modules.mnt.service.dto.DeployHistoryQueryCriteria; +import me.zhengjie.modules.mnt.service.mapstruct.DeployHistoryMapper; +import me.zhengjie.utils.FileUtil; +import me.zhengjie.utils.PageUtil; +import me.zhengjie.utils.QueryHelp; +import me.zhengjie.utils.ValidationUtil; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Service +@RequiredArgsConstructor +public class DeployHistoryServiceImpl implements DeployHistoryService { + + private final DeployHistoryRepository deployhistoryRepository; + private final DeployHistoryMapper deployhistoryMapper; + + @Override + public Object queryAll(DeployHistoryQueryCriteria criteria, Pageable pageable){ + Page page = deployhistoryRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); + return PageUtil.toPage(page.map(deployhistoryMapper::toDto)); + } + + @Override + public List queryAll(DeployHistoryQueryCriteria criteria){ + return deployhistoryMapper.toDto(deployhistoryRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder))); + } + + @Override + public DeployHistoryDto findById(String id) { + DeployHistory deployhistory = deployhistoryRepository.findById(id).orElseGet(DeployHistory::new); + ValidationUtil.isNull(deployhistory.getId(),"DeployHistory","id",id); + return deployhistoryMapper.toDto(deployhistory); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(DeployHistory resources) { + resources.setId(IdUtil.simpleUUID()); + deployhistoryRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + for (String id : ids) { + deployhistoryRepository.deleteById(id); + } + } + + @Override + public void download(List queryAll, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (DeployHistoryDto deployHistoryDto : queryAll) { + Map map = new LinkedHashMap<>(); + map.put("部署编号", deployHistoryDto.getDeployId()); + map.put("应用名称", deployHistoryDto.getAppName()); + map.put("部署IP", deployHistoryDto.getIp()); + map.put("部署时间", deployHistoryDto.getDeployDate()); + map.put("部署人员", deployHistoryDto.getDeployUser()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/DeployServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/DeployServiceImpl.java new file mode 100644 index 0000000..f2491cd --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/DeployServiceImpl.java @@ -0,0 +1,430 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.impl; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.mnt.domain.App; +import me.zhengjie.modules.mnt.domain.Deploy; +import me.zhengjie.modules.mnt.domain.DeployHistory; +import me.zhengjie.modules.mnt.domain.ServerDeploy; +import me.zhengjie.modules.mnt.repository.DeployRepository; +import me.zhengjie.modules.mnt.service.DeployHistoryService; +import me.zhengjie.modules.mnt.service.DeployService; +import me.zhengjie.modules.mnt.service.ServerDeployService; +import me.zhengjie.modules.mnt.service.dto.AppDto; +import me.zhengjie.modules.mnt.service.dto.DeployDto; +import me.zhengjie.modules.mnt.service.dto.DeployQueryCriteria; +import me.zhengjie.modules.mnt.service.dto.ServerDeployDto; +import me.zhengjie.modules.mnt.service.mapstruct.DeployMapper; +import me.zhengjie.modules.mnt.util.ExecuteShellUtil; +import me.zhengjie.modules.mnt.util.ScpClientUtil; +import me.zhengjie.modules.mnt.websocket.MsgType; +import me.zhengjie.modules.mnt.websocket.SocketMsg; +import me.zhengjie.modules.mnt.websocket.WebSocketServer; +import me.zhengjie.utils.*; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** + * @author zhanghouying + * @date 2019-08-24 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class DeployServiceImpl implements DeployService { + + private final String FILE_SEPARATOR = "/"; + private final DeployRepository deployRepository; + private final DeployMapper deployMapper; + private final ServerDeployService serverDeployService; + private final DeployHistoryService deployHistoryService; + /** + * 循环次数 + */ + private final Integer count = 30; + + + @Override + public Object queryAll(DeployQueryCriteria criteria, Pageable pageable) { + Page page = deployRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable); + return PageUtil.toPage(page.map(deployMapper::toDto)); + } + + @Override + public List queryAll(DeployQueryCriteria criteria) { + return deployMapper.toDto(deployRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder))); + } + + @Override + public DeployDto findById(Long id) { + Deploy deploy = deployRepository.findById(id).orElseGet(Deploy::new); + ValidationUtil.isNull(deploy.getId(), "Deploy", "id", id); + return deployMapper.toDto(deploy); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Deploy resources) { + deployRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(Deploy resources) { + Deploy deploy = deployRepository.findById(resources.getId()).orElseGet(Deploy::new); + ValidationUtil.isNull(deploy.getId(), "Deploy", "id", resources.getId()); + deploy.copy(resources); + deployRepository.save(deploy); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + for (Long id : ids) { + deployRepository.deleteById(id); + } + } + + @Override + public void deploy(String fileSavePath, Long id) { + deployApp(fileSavePath, id); + } + + /** + * @param fileSavePath 本机路径 + * @param id ID + */ + private void deployApp(String fileSavePath, Long id) { + + DeployDto deploy = findById(id); + if (deploy == null) { + sendMsg("部署信息不存在", MsgType.ERROR); + throw new BadRequestException("部署信息不存在"); + } + AppDto app = deploy.getApp(); + if (app == null) { + sendMsg("包对应应用信息不存在", MsgType.ERROR); + throw new BadRequestException("包对应应用信息不存在"); + } + int port = app.getPort(); + //这个是服务器部署路径 + String uploadPath = app.getUploadPath(); + StringBuilder sb = new StringBuilder(); + String msg; + Set deploys = deploy.getDeploys(); + for (ServerDeployDto deployDTO : deploys) { + String ip = deployDTO.getIp(); + ExecuteShellUtil executeShellUtil = getExecuteShellUtil(ip); + //判断是否第一次部署 + boolean flag = checkFile(executeShellUtil, app); + //第一步要确认服务器上有这个目录 + executeShellUtil.execute("mkdir -p " + app.getUploadPath()); + executeShellUtil.execute("mkdir -p " + app.getBackupPath()); + executeShellUtil.execute("mkdir -p " + app.getDeployPath()); + //上传文件 + msg = String.format("登陆到服务器:%s", ip); + ScpClientUtil scpClientUtil = getScpClientUtil(ip); + log.info(msg); + sendMsg(msg, MsgType.INFO); + msg = String.format("上传文件到服务器:%s
目录:%s下,请稍等...", ip, uploadPath); + sendMsg(msg, MsgType.INFO); + scpClientUtil.putFile(fileSavePath, uploadPath); + if (flag) { + sendMsg("停止原来应用", MsgType.INFO); + //停止应用 + stopApp(port, executeShellUtil); + sendMsg("备份原来应用", MsgType.INFO); + //备份应用 + backupApp(executeShellUtil, ip, app.getDeployPath()+FILE_SEPARATOR, app.getName(), app.getBackupPath()+FILE_SEPARATOR, id); + } + sendMsg("部署应用", MsgType.INFO); + //部署文件,并启动应用 + String deployScript = app.getDeployScript(); + executeShellUtil.execute(deployScript); + sleep(3); + sendMsg("应用部署中,请耐心等待部署结果,或者稍后手动查看部署状态", MsgType.INFO); + int i = 0; + boolean result = false; + // 由于启动应用需要时间,所以需要循环获取状态,如果超过30次,则认为是启动失败 + while (i++ < count){ + result = checkIsRunningStatus(port, executeShellUtil); + if(result){ + break; + } + // 休眠6秒 + sleep(6); + } + sb.append("服务器:").append(deployDTO.getName()).append("
应用:").append(app.getName()); + sendResultMsg(result, sb); + executeShellUtil.close(); + } + } + + private void sleep(int second) { + try { + Thread.sleep(second * 1000); + } catch (InterruptedException e) { + log.error(e.getMessage(),e); + } + } + + private void backupApp(ExecuteShellUtil executeShellUtil, String ip, String fileSavePath, String appName, String backupPath, Long id) { + String deployDate = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN); + StringBuilder sb = new StringBuilder(); + backupPath += appName + FILE_SEPARATOR + deployDate + "\n"; + sb.append("mkdir -p ").append(backupPath); + sb.append("mv -f ").append(fileSavePath); + sb.append(appName).append(" ").append(backupPath); + log.info("备份应用脚本:" + sb.toString()); + executeShellUtil.execute(sb.toString()); + //还原信息入库 + DeployHistory deployHistory = new DeployHistory(); + deployHistory.setAppName(appName); + deployHistory.setDeployUser(SecurityUtils.getCurrentUsername()); + deployHistory.setIp(ip); + deployHistory.setDeployId(id); + deployHistoryService.create(deployHistory); + } + + /** + * 停App + * + * @param port 端口 + * @param executeShellUtil / + */ + private void stopApp(int port, ExecuteShellUtil executeShellUtil) { + //发送停止命令 + executeShellUtil.execute(String.format("lsof -i :%d|grep -v \"PID\"|awk '{print \"kill -9\",$2}'|sh", port)); + + } + + /** + * 指定端口程序是否在运行 + * + * @param port 端口 + * @param executeShellUtil / + * @return true 正在运行 false 已经停止 + */ + private boolean checkIsRunningStatus(int port, ExecuteShellUtil executeShellUtil) { + String result = executeShellUtil.executeForResult(String.format("fuser -n tcp %d", port)); + return result.indexOf("/tcp:")>0; + } + + private void sendMsg(String msg, MsgType msgType) { + try { + WebSocketServer.sendInfo(new SocketMsg(msg, msgType), "deploy"); + } catch (IOException e) { + log.error(e.getMessage(),e); + } + } + + @Override + public String serverStatus(Deploy resources) { + Set serverDeploys = resources.getDeploys(); + App app = resources.getApp(); + for (ServerDeploy serverDeploy : serverDeploys) { + StringBuilder sb = new StringBuilder(); + ExecuteShellUtil executeShellUtil = getExecuteShellUtil(serverDeploy.getIp()); + sb.append("服务器:").append(serverDeploy.getName()).append("
应用:").append(app.getName()); + boolean result = checkIsRunningStatus(app.getPort(), executeShellUtil); + if (result) { + sb.append("
正在运行"); + sendMsg(sb.toString(), MsgType.INFO); + } else { + sb.append("
已停止!"); + sendMsg(sb.toString(), MsgType.ERROR); + } + log.info(sb.toString()); + executeShellUtil.close(); + } + return "执行完毕"; + } + + private boolean checkFile(ExecuteShellUtil executeShellUtil, AppDto appDTO) { + String result = executeShellUtil.executeForResult("find " + appDTO.getDeployPath() + " -name " + appDTO.getName()); + return result.indexOf(appDTO.getName())>0; + } + + /** + * 启动服务 + * @param resources / + * @return / + */ + @Override + public String startServer(Deploy resources) { + Set deploys = resources.getDeploys(); + App app = resources.getApp(); + for (ServerDeploy deploy : deploys) { + StringBuilder sb = new StringBuilder(); + ExecuteShellUtil executeShellUtil = getExecuteShellUtil(deploy.getIp()); + //为了防止重复启动,这里先停止应用 + stopApp(app.getPort(), executeShellUtil); + sb.append("服务器:").append(deploy.getName()).append("
应用:").append(app.getName()); + sendMsg("下发启动命令", MsgType.INFO); + executeShellUtil.execute(app.getStartScript()); + sleep(3); + sendMsg("应用启动中,请耐心等待启动结果,或者稍后手动查看运行状态", MsgType.INFO); + int i = 0; + boolean result = false; + // 由于启动应用需要时间,所以需要循环获取状态,如果超过30次,则认为是启动失败 + while (i++ < count){ + result = checkIsRunningStatus(app.getPort(), executeShellUtil); + if(result){ + break; + } + // 休眠6秒 + sleep(6); + } + sendResultMsg(result, sb); + log.info(sb.toString()); + executeShellUtil.close(); + } + return "执行完毕"; + } + + /** + * 停止服务 + * @param resources / + * @return / + */ + @Override + public String stopServer(Deploy resources) { + Set deploys = resources.getDeploys(); + App app = resources.getApp(); + for (ServerDeploy deploy : deploys) { + StringBuilder sb = new StringBuilder(); + ExecuteShellUtil executeShellUtil = getExecuteShellUtil(deploy.getIp()); + sb.append("服务器:").append(deploy.getName()).append("
应用:").append(app.getName()); + sendMsg("下发停止命令", MsgType.INFO); + //停止应用 + stopApp(app.getPort(), executeShellUtil); + sleep(1); + boolean result = checkIsRunningStatus(app.getPort(), executeShellUtil); + if (result) { + sb.append("
关闭失败!"); + sendMsg(sb.toString(), MsgType.ERROR); + } else { + sb.append("
关闭成功!"); + sendMsg(sb.toString(), MsgType.INFO); + } + log.info(sb.toString()); + executeShellUtil.close(); + } + return "执行完毕"; + } + + @Override + public String serverReduction(DeployHistory resources) { + Long deployId = resources.getDeployId(); + Deploy deployInfo = deployRepository.findById(deployId).orElseGet(Deploy::new); + String deployDate = DateUtil.format(resources.getDeployDate(), DatePattern.PURE_DATETIME_PATTERN); + App app = deployInfo.getApp(); + if (app == null) { + sendMsg("应用信息不存在:" + resources.getAppName(), MsgType.ERROR); + throw new BadRequestException("应用信息不存在:" + resources.getAppName()); + } + String backupPath = app.getBackupPath()+FILE_SEPARATOR; + backupPath += resources.getAppName() + FILE_SEPARATOR + deployDate; + //这个是服务器部署路径 + String deployPath = app.getDeployPath(); + String ip = resources.getIp(); + ExecuteShellUtil executeShellUtil = getExecuteShellUtil(ip); + String msg; + + msg = String.format("登陆到服务器:%s", ip); + log.info(msg); + sendMsg(msg, MsgType.INFO); + sendMsg("停止原来应用", MsgType.INFO); + //停止应用 + stopApp(app.getPort(), executeShellUtil); + //删除原来应用 + sendMsg("删除应用", MsgType.INFO); + executeShellUtil.execute("rm -rf " + deployPath + FILE_SEPARATOR + resources.getAppName()); + //还原应用 + sendMsg("还原应用", MsgType.INFO); + executeShellUtil.execute("cp -r " + backupPath + "/. " + deployPath); + sendMsg("启动应用", MsgType.INFO); + executeShellUtil.execute(app.getStartScript()); + sendMsg("应用启动中,请耐心等待启动结果,或者稍后手动查看启动状态", MsgType.INFO); + int i = 0; + boolean result = false; + // 由于启动应用需要时间,所以需要循环获取状态,如果超过30次,则认为是启动失败 + while (i++ < count){ + result = checkIsRunningStatus(app.getPort(), executeShellUtil); + if(result){ + break; + } + // 休眠6秒 + sleep(6); + } + StringBuilder sb = new StringBuilder(); + sb.append("服务器:").append(ip).append("
应用:").append(resources.getAppName()); + sendResultMsg(result, sb); + executeShellUtil.close(); + return ""; + } + + private ExecuteShellUtil getExecuteShellUtil(String ip) { + ServerDeployDto serverDeployDTO = serverDeployService.findByIp(ip); + if (serverDeployDTO == null) { + sendMsg("IP对应服务器信息不存在:" + ip, MsgType.ERROR); + throw new BadRequestException("IP对应服务器信息不存在:" + ip); + } + return new ExecuteShellUtil(ip, serverDeployDTO.getAccount(), serverDeployDTO.getPassword(),serverDeployDTO.getPort()); + } + + private ScpClientUtil getScpClientUtil(String ip) { + ServerDeployDto serverDeployDTO = serverDeployService.findByIp(ip); + if (serverDeployDTO == null) { + sendMsg("IP对应服务器信息不存在:" + ip, MsgType.ERROR); + throw new BadRequestException("IP对应服务器信息不存在:" + ip); + } + return ScpClientUtil.getInstance(ip, serverDeployDTO.getPort(), serverDeployDTO.getAccount(), serverDeployDTO.getPassword()); + } + + private void sendResultMsg(boolean result, StringBuilder sb) { + if (result) { + sb.append("
启动成功!"); + sendMsg(sb.toString(), MsgType.INFO); + } else { + sb.append("
启动失败!"); + sendMsg(sb.toString(), MsgType.ERROR); + } + } + + @Override + public void download(List queryAll, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (DeployDto deployDto : queryAll) { + Map map = new LinkedHashMap<>(); + map.put("应用名称", deployDto.getApp().getName()); + map.put("服务器", deployDto.getServers()); + map.put("部署日期", deployDto.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/ServerDeployServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/ServerDeployServiceImpl.java new file mode 100644 index 0000000..63272da --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/impl/ServerDeployServiceImpl.java @@ -0,0 +1,125 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.impl; + +import lombok.RequiredArgsConstructor; +import me.zhengjie.modules.mnt.domain.ServerDeploy; +import me.zhengjie.modules.mnt.repository.ServerDeployRepository; +import me.zhengjie.modules.mnt.service.ServerDeployService; +import me.zhengjie.modules.mnt.service.dto.ServerDeployDto; +import me.zhengjie.modules.mnt.service.dto.ServerDeployQueryCriteria; +import me.zhengjie.modules.mnt.service.mapstruct.ServerDeployMapper; +import me.zhengjie.modules.mnt.util.ExecuteShellUtil; +import me.zhengjie.utils.FileUtil; +import me.zhengjie.utils.PageUtil; +import me.zhengjie.utils.QueryHelp; +import me.zhengjie.utils.ValidationUtil; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Service +@RequiredArgsConstructor +public class ServerDeployServiceImpl implements ServerDeployService { + + private final ServerDeployRepository serverDeployRepository; + private final ServerDeployMapper serverDeployMapper; + + @Override + public Object queryAll(ServerDeployQueryCriteria criteria, Pageable pageable){ + Page page = serverDeployRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); + return PageUtil.toPage(page.map(serverDeployMapper::toDto)); + } + + @Override + public List queryAll(ServerDeployQueryCriteria criteria){ + return serverDeployMapper.toDto(serverDeployRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder))); + } + + @Override + public ServerDeployDto findById(Long id) { + ServerDeploy server = serverDeployRepository.findById(id).orElseGet(ServerDeploy::new); + ValidationUtil.isNull(server.getId(),"ServerDeploy","id",id); + return serverDeployMapper.toDto(server); + } + + @Override + public ServerDeployDto findByIp(String ip) { + ServerDeploy deploy = serverDeployRepository.findByIp(ip); + return serverDeployMapper.toDto(deploy); + } + + @Override + public Boolean testConnect(ServerDeploy resources) { + ExecuteShellUtil executeShellUtil = null; + try { + executeShellUtil = new ExecuteShellUtil(resources.getIp(), resources.getAccount(), resources.getPassword(),resources.getPort()); + return executeShellUtil.execute("ls")==0; + } catch (Exception e) { + return false; + }finally { + if (executeShellUtil != null) { + executeShellUtil.close(); + } + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(ServerDeploy resources) { + serverDeployRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(ServerDeploy resources) { + ServerDeploy serverDeploy = serverDeployRepository.findById(resources.getId()).orElseGet(ServerDeploy::new); + ValidationUtil.isNull( serverDeploy.getId(),"ServerDeploy","id",resources.getId()); + serverDeploy.copy(resources); + serverDeployRepository.save(serverDeploy); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + for (Long id : ids) { + serverDeployRepository.deleteById(id); + } + } + + @Override + public void download(List queryAll, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (ServerDeployDto deployDto : queryAll) { + Map map = new LinkedHashMap<>(); + map.put("服务器名称", deployDto.getName()); + map.put("服务器IP", deployDto.getIp()); + map.put("端口", deployDto.getPort()); + map.put("账号", deployDto.getAccount()); + map.put("创建日期", deployDto.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/AppMapper.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/AppMapper.java new file mode 100644 index 0000000..fc39eeb --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/AppMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.modules.mnt.domain.App; +import me.zhengjie.modules.mnt.service.dto.AppDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Mapper(componentModel = "spring",uses = {},unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface AppMapper extends BaseMapper { + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/DatabaseMapper.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/DatabaseMapper.java new file mode 100644 index 0000000..3cc6e8d --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/DatabaseMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.modules.mnt.domain.Database; +import me.zhengjie.modules.mnt.service.dto.DatabaseDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DatabaseMapper extends BaseMapper { + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/DeployHistoryMapper.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/DeployHistoryMapper.java new file mode 100644 index 0000000..2522ab0 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/DeployHistoryMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.modules.mnt.domain.DeployHistory; +import me.zhengjie.modules.mnt.service.dto.DeployHistoryDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Mapper(componentModel = "spring",uses = {},unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DeployHistoryMapper extends BaseMapper { + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/DeployMapper.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/DeployMapper.java new file mode 100644 index 0000000..cd3edee --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/DeployMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.modules.mnt.domain.Deploy; +import me.zhengjie.modules.mnt.service.dto.DeployDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Mapper(componentModel = "spring",uses = {AppMapper.class, ServerDeployMapper.class},unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DeployMapper extends BaseMapper { + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/ServerDeployMapper.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/ServerDeployMapper.java new file mode 100644 index 0000000..960b25b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/service/mapstruct/ServerDeployMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.modules.mnt.domain.ServerDeploy; +import me.zhengjie.modules.mnt.service.dto.ServerDeployDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Mapper(componentModel = "spring",uses = {},unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface ServerDeployMapper extends BaseMapper { + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/util/DataTypeEnum.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/util/DataTypeEnum.java new file mode 100644 index 0000000..e104b9e --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/util/DataTypeEnum.java @@ -0,0 +1,140 @@ +/* + * << + * Davinci + * == + * Copyright (C) 2016 - 2019 EDP + * == + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * >> + * + */ + +package me.zhengjie.modules.mnt.util; +import lombok.extern.slf4j.Slf4j; + +/** + * @author / + */ +@Slf4j +@SuppressWarnings({"unchecked","all"}) +public enum DataTypeEnum { + + /** mysql */ + MYSQL("mysql", "mysql", "com.mysql.jdbc.Driver", "`", "`", "'", "'"), + + /** oracle */ + ORACLE("oracle", "oracle", "oracle.jdbc.driver.OracleDriver", "\"", "\"", "\"", "\""), + + /** sql server */ + SQLSERVER("sqlserver", "sqlserver", "com.microsoft.sqlserver.jdbc.SQLServerDriver", "\"", "\"", "\"", "\""), + + /** h2 */ + H2("h2", "h2", "org.h2.Driver", "`", "`", "\"", "\""), + + /** phoenix */ + PHOENIX("phoenix", "hbase phoenix", "org.apache.phoenix.jdbc.PhoenixDriver", "", "", "\"", "\""), + + /** mongo */ + MONGODB("mongo", "mongodb", "mongodb.jdbc.MongoDriver", "`", "`", "\"", "\""), + + /** sql4es */ + ELASTICSEARCH("sql4es", "elasticsearch", "nl.anchormen.sql4es.jdbc.ESDriver", "", "", "'", "'"), + + /** presto */ + PRESTO("presto", "presto", "com.facebook.presto.jdbc.PrestoDriver", "", "", "\"", "\""), + + /** moonbox */ + MOONBOX("moonbox", "moonbox", "moonbox.jdbc.MbDriver", "`", "`", "`", "`"), + + /** cassandra */ + CASSANDRA("cassandra", "cassandra", "com.github.adejanovski.cassandra.jdbc.CassandraDriver", "", "", "'", "'"), + + /** click house */ + CLICKHOUSE("clickhouse", "clickhouse", "ru.yandex.clickhouse.ClickHouseDriver", "", "", "\"", "\""), + + /** kylin */ + KYLIN("kylin", "kylin", "org.apache.kylin.jdbc.Driver", "\"", "\"", "\"", "\""), + + /** vertica */ + VERTICA("vertica", "vertica", "com.vertica.jdbc.Driver", "", "", "'", "'"), + + /** sap */ + HANA("sap", "sap hana", "com.sap.db.jdbc.Driver", "", "", "'", "'"), + + /** impala */ + IMPALA("impala", "impala", "com.cloudera.impala.jdbc41.Driver", "", "", "'", "'"); + + private String feature; + private String desc; + private String driver; + private String keywordPrefix; + private String keywordSuffix; + private String aliasPrefix; + private String aliasSuffix; + + private static final String JDBC_URL_PREFIX = "jdbc:"; + + DataTypeEnum(String feature, String desc, String driver, String keywordPrefix, String keywordSuffix, String aliasPrefix, String aliasSuffix) { + this.feature = feature; + this.desc = desc; + this.driver = driver; + this.keywordPrefix = keywordPrefix; + this.keywordSuffix = keywordSuffix; + this.aliasPrefix = aliasPrefix; + this.aliasSuffix = aliasSuffix; + } + + public static DataTypeEnum urlOf(String jdbcUrl) { + String url = jdbcUrl.toLowerCase().trim(); + for (DataTypeEnum dataTypeEnum : values()) { + if (url.startsWith(JDBC_URL_PREFIX + dataTypeEnum.feature)) { + try { + Class aClass = Class.forName(dataTypeEnum.getDriver()); + if (null == aClass) { + throw new RuntimeException("Unable to get driver instance for jdbcUrl: " + jdbcUrl); + } + } catch (ClassNotFoundException e) { + throw new RuntimeException("Unable to get driver instance: " + jdbcUrl); + } + return dataTypeEnum; + } + } + return null; + } + + public String getFeature() { + return feature; + } + + public String getDesc() { + return desc; + } + + public String getDriver() { + return driver; + } + + public String getKeywordPrefix() { + return keywordPrefix; + } + + public String getKeywordSuffix() { + return keywordSuffix; + } + + public String getAliasPrefix() { + return aliasPrefix; + } + + public String getAliasSuffix() { + return aliasSuffix; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/util/ExecuteShellUtil.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/util/ExecuteShellUtil.java new file mode 100644 index 0000000..a5d5b59 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/util/ExecuteShellUtil.java @@ -0,0 +1,101 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.util; + +import cn.hutool.core.io.IoUtil; +import com.jcraft.jsch.ChannelShell; +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.Session; +import lombok.extern.slf4j.Slf4j; + +import java.io.*; +import java.util.Vector; + +/** + * 执行shell命令 + * + * @author: ZhangHouYing + * @date: 2019/8/10 + */ +@Slf4j +public class ExecuteShellUtil { + + private Vector stdout; + + Session session; + + public ExecuteShellUtil(final String ipAddress, final String username, final String password,int port) { + try { + JSch jsch = new JSch(); + session = jsch.getSession(username, ipAddress, port); + session.setPassword(password); + session.setConfig("StrictHostKeyChecking", "no"); + session.connect(3000); + } catch (Exception e) { + log.error(e.getMessage(),e); + } + + } + + public int execute(final String command) { + int returnCode = 0; + ChannelShell channel = null; + PrintWriter printWriter = null; + BufferedReader input = null; + stdout = new Vector(); + try { + channel = (ChannelShell) session.openChannel("shell"); + channel.connect(); + input = new BufferedReader(new InputStreamReader(channel.getInputStream())); + printWriter = new PrintWriter(channel.getOutputStream()); + printWriter.println(command); + printWriter.println("exit"); + printWriter.flush(); + log.info("The remote command is: "); + String line; + while ((line = input.readLine()) != null) { + stdout.add(line); + System.out.println(line); + } + } catch (Exception e) { + log.error(e.getMessage(),e); + return -1; + }finally { + IoUtil.close(printWriter); + IoUtil.close(input); + if (channel != null) { + channel.disconnect(); + } + } + return returnCode; + } + + public void close(){ + if (session != null) { + session.disconnect(); + } + } + + public String executeForResult(String command) { + execute(command); + StringBuilder sb = new StringBuilder(); + for (String str : stdout) { + sb.append(str); + } + return sb.toString(); + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/util/ScpClientUtil.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/util/ScpClientUtil.java new file mode 100644 index 0000000..7cb83aa --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/util/ScpClientUtil.java @@ -0,0 +1,105 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.util; + +import ch.ethz.ssh2.Connection; +import ch.ethz.ssh2.SCPClient; +import com.google.common.collect.Maps; + +import java.io.IOException; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * 远程执行linux命令 + * @author: ZhangHouYing + * @date: 2019-08-10 10:06 + */ +public class ScpClientUtil { + + static private Map instance = Maps.newHashMap(); + + static synchronized public ScpClientUtil getInstance(String ip, int port, String username, String password) { + if (instance.get(ip) == null) { + instance.put(ip, new ScpClientUtil(ip, port, username, password)); + } + return instance.get(ip); + } + + public ScpClientUtil(String ip, int port, String username, String password) { + this.ip = ip; + this.port = port; + this.username = username; + this.password = password; + } + + public void getFile(String remoteFile, String localTargetDirectory) { + Connection conn = new Connection(ip, port); + try { + conn.connect(); + boolean isAuthenticated = conn.authenticateWithPassword(username, password); + if (!isAuthenticated) { + System.err.println("authentication failed"); + } + SCPClient client = new SCPClient(conn); + client.get(remoteFile, localTargetDirectory); + } catch (IOException ex) { + Logger.getLogger(SCPClient.class.getName()).log(Level.SEVERE, null, ex); + }finally{ + conn.close(); + } + } + + public void putFile(String localFile, String remoteTargetDirectory) { + putFile(localFile, null, remoteTargetDirectory); + } + + public void putFile(String localFile, String remoteFileName, String remoteTargetDirectory) { + putFile(localFile, remoteFileName, remoteTargetDirectory,null); + } + + public void putFile(String localFile, String remoteFileName, String remoteTargetDirectory, String mode) { + Connection conn = new Connection(ip, port); + try { + conn.connect(); + boolean isAuthenticated = conn.authenticateWithPassword(username, password); + if (!isAuthenticated) { + System.err.println("authentication failed"); + } + SCPClient client = new SCPClient(conn); + if ((mode == null) || (mode.length() == 0)) { + mode = "0600"; + } + if (remoteFileName == null) { + client.put(localFile, remoteTargetDirectory); + } else { + client.put(localFile, remoteFileName, remoteTargetDirectory, mode); + } + } catch (IOException ex) { + Logger.getLogger(ScpClientUtil.class.getName()).log(Level.SEVERE, null, ex); + }finally{ + conn.close(); + } + } + + private String ip; + private int port; + private String username; + private String password; + + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/util/SqlUtils.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/util/SqlUtils.java new file mode 100644 index 0000000..d7e06b1 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/util/SqlUtils.java @@ -0,0 +1,201 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.util; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.util.StringUtils; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.utils.CloseUtil; +import javax.sql.DataSource; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.sql.*; +import java.util.List; + +/** + * @author / + */ +@Slf4j +public class SqlUtils { + + /** + * 获取数据源 + * + * @param jdbcUrl / + * @param userName / + * @param password / + * @return DataSource + */ + private static DataSource getDataSource(String jdbcUrl, String userName, String password) { + DruidDataSource druidDataSource = new DruidDataSource(); + String className; + try { + className = DriverManager.getDriver(jdbcUrl.trim()).getClass().getName(); + } catch (SQLException e) { + throw new RuntimeException("Get class name error: =" + jdbcUrl); + } + if (StringUtils.isEmpty(className)) { + DataTypeEnum dataTypeEnum = DataTypeEnum.urlOf(jdbcUrl); + if (null == dataTypeEnum) { + throw new RuntimeException("Not supported data type: jdbcUrl=" + jdbcUrl); + } + druidDataSource.setDriverClassName(dataTypeEnum.getDriver()); + } else { + druidDataSource.setDriverClassName(className); + } + + + druidDataSource.setUrl(jdbcUrl); + druidDataSource.setUsername(userName); + druidDataSource.setPassword(password); + // 配置获取连接等待超时的时间 + druidDataSource.setMaxWait(3000); + // 配置初始化大小、最小、最大 + druidDataSource.setInitialSize(1); + druidDataSource.setMinIdle(1); + druidDataSource.setMaxActive(1); + + // 如果链接出现异常则直接判定为失败而不是一直重试 + druidDataSource.setBreakAfterAcquireFailure(true); + try { + druidDataSource.init(); + } catch (SQLException e) { + log.error("Exception during pool initialization", e); + throw new RuntimeException(e.getMessage()); + } + + return druidDataSource; + } + + private static Connection getConnection(String jdbcUrl, String userName, String password) { + DataSource dataSource = getDataSource(jdbcUrl, userName, password); + Connection connection = null; + try { + connection = dataSource.getConnection(); + } catch (Exception ignored) {} + try { + int timeOut = 5; + if (null == connection || connection.isClosed() || !connection.isValid(timeOut)) { + log.info("connection is closed or invalid, retry get connection!"); + connection = dataSource.getConnection(); + } + } catch (Exception e) { + log.error("create connection error, jdbcUrl: {}", jdbcUrl); + throw new RuntimeException("create connection error, jdbcUrl: " + jdbcUrl); + } finally { + CloseUtil.close(connection); + } + return connection; + } + + private static void releaseConnection(Connection connection) { + if (null != connection) { + try { + connection.close(); + } catch (Exception e) { + log.error(e.getMessage(),e); + log.error("connection close error:" + e.getMessage()); + } + } + } + + public static boolean testConnection(String jdbcUrl, String userName, String password) { + Connection connection = null; + try { + connection = getConnection(jdbcUrl, userName, password); + if (null != connection) { + return true; + } + } catch (Exception e) { + log.info("Get connection failed:" + e.getMessage()); + } finally { + releaseConnection(connection); + } + return false; + } + + public static String executeFile(String jdbcUrl, String userName, String password, File sqlFile) { + Connection connection = getConnection(jdbcUrl, userName, password); + try { + batchExecute(connection, readSqlList(sqlFile)); + } catch (Exception e) { + log.error("sql脚本执行发生异常:{}",e.getMessage()); + return e.getMessage(); + }finally { + releaseConnection(connection); + } + return "success"; + } + + + /** + * 批量执行sql + * @param connection / + * @param sqlList / + */ + public static void batchExecute(Connection connection, List sqlList) { + Statement st = null; + try { + st = connection.createStatement(); + for (String sql : sqlList) { + if (sql.endsWith(";")) { + sql = sql.substring(0, sql.length() - 1); + } + st.addBatch(sql); + } + st.executeBatch(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } finally { + CloseUtil.close(st); + } + } + + /** + * 将文件中的sql语句以;为单位读取到列表中 + * @param sqlFile / + * @return / + * @throws Exception e + */ + private static List readSqlList(File sqlFile) throws Exception { + List sqlList = Lists.newArrayList(); + StringBuilder sb = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader( + new FileInputStream(sqlFile), StandardCharsets.UTF_8))) { + String tmp; + while ((tmp = reader.readLine()) != null) { + log.info("line:{}", tmp); + if (tmp.endsWith(";")) { + sb.append(tmp); + sqlList.add(sb.toString()); + sb.delete(0, sb.length()); + } else { + sb.append(tmp); + } + } + if (!"".endsWith(sb.toString().trim())) { + sqlList.add(sb.toString()); + } + } + + return sqlList; + } + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/websocket/MsgType.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/websocket/MsgType.java new file mode 100644 index 0000000..2fc473d --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/websocket/MsgType.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.websocket; + +/** + * @author ZhangHouYing + * @date 2019-08-10 9:56 + */ +public enum MsgType { + /** 连接 */ + CONNECT, + /** 关闭 */ + CLOSE, + /** 信息 */ + INFO, + /** 错误 */ + ERROR +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/websocket/SocketMsg.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/websocket/SocketMsg.java new file mode 100644 index 0000000..ade33a2 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/websocket/SocketMsg.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.websocket; + +import lombok.Data; + +/** + * @author ZhangHouYing + * @date 2019-08-10 9:55 + */ +@Data +public class SocketMsg { + private String msg; + private MsgType msgType; + + public SocketMsg(String msg, MsgType msgType) { + this.msg = msg; + this.msgType = msgType; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/mnt/websocket/WebSocketServer.java b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/websocket/WebSocketServer.java new file mode 100644 index 0000000..9c92165 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/mnt/websocket/WebSocketServer.java @@ -0,0 +1,139 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.mnt.websocket; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.websocket.*; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; +import java.io.IOException; +import java.util.Objects; +import java.util.concurrent.CopyOnWriteArraySet; +/** + * @author ZhangHouYing + * @date 2019-08-10 15:46 + */ +@ServerEndpoint("/webSocket/{sid}") +@Slf4j +@Component +public class WebSocketServer { + + /** + * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。 + */ + private static CopyOnWriteArraySet webSocketSet = new CopyOnWriteArraySet(); + + /** + * 与某个客户端的连接会话,需要通过它来给客户端发送数据 + */ + private Session session; + + /** + * 接收sid + */ + private String sid=""; + /** + * 连接建立成功调用的方法 + * */ + @OnOpen + public void onOpen(Session session,@PathParam("sid") String sid) { + this.session = session; + //如果存在就先删除一个,防止重复推送消息 + for (WebSocketServer webSocket:webSocketSet) { + if (webSocket.sid.equals(sid)) { + webSocketSet.remove(webSocket); + } + } + webSocketSet.add(this); + this.sid=sid; + } + + /** + * 连接关闭调用的方法 + */ + @OnClose + public void onClose() { + webSocketSet.remove(this); + } + + /** + * 收到客户端消息后调用的方法 + * @param message 客户端发送过来的消息*/ + @OnMessage + public void onMessage(String message, Session session) { + log.info("收到来"+sid+"的信息:"+message); + //群发消息 + for (WebSocketServer item : webSocketSet) { + try { + item.sendMessage(message); + } catch (IOException e) { + log.error(e.getMessage(),e); + } + } + } + + @OnError + public void onError(Session session, Throwable error) { + log.error("发生错误"); + error.printStackTrace(); + } + /** + * 实现服务器主动推送 + */ + private void sendMessage(String message) throws IOException { + this.session.getBasicRemote().sendText(message); + } + + + /** + * 群发自定义消息 + * */ + public static void sendInfo(SocketMsg socketMsg,@PathParam("sid") String sid) throws IOException { + String message = JSONObject.toJSONString(socketMsg); + log.info("推送消息到"+sid+",推送内容:"+message); + for (WebSocketServer item : webSocketSet) { + try { + //这里可以设定只推送给这个sid的,为null则全部推送 + if(sid==null) { + item.sendMessage(message); + }else if(item.sid.equals(sid)){ + item.sendMessage(message); + } + } catch (IOException ignored) { } + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + WebSocketServer that = (WebSocketServer) o; + return Objects.equals(session, that.session) && + Objects.equals(sid, that.sid); + } + + @Override + public int hashCode() { + return Objects.hash(session, sid); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/config/JobRunner.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/config/JobRunner.java new file mode 100644 index 0000000..9b903e9 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/config/JobRunner.java @@ -0,0 +1,54 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.config; + +import cn.hutool.json.JSONUtil; +import lombok.RequiredArgsConstructor; +import me.zhengjie.modules.quartz.domain.QuartzJob; +import me.zhengjie.modules.quartz.repository.QuartzJobRepository; +import me.zhengjie.modules.quartz.utils.QuartzManage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +@Component +@RequiredArgsConstructor +public class JobRunner implements ApplicationRunner { + private static final Logger log = LoggerFactory.getLogger(JobRunner.class); + private final QuartzJobRepository quartzJobRepository; + private final QuartzManage quartzManage; + + /** + * 项目启动时重新激活启用的定时任务 + * + * @param applicationArguments / + */ + @Override + public void run(ApplicationArguments applicationArguments) { + log.info("--------------------注入定时任务---------------------"); + List quartzJobs = quartzJobRepository.findByIsPauseIsFalse(); + quartzJobs.forEach(quartzManage::addJob); + log.info("--------------------定时任务注入完成---------------------"); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/config/QuartzConfig.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/config/QuartzConfig.java new file mode 100644 index 0000000..99f2e50 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/config/QuartzConfig.java @@ -0,0 +1,52 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.config; + +import org.quartz.spi.TriggerFiredBundle; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.quartz.AdaptableJobFactory; +import org.springframework.stereotype.Component; + +/** + * 定时任务配置 + * @author / + * @date 2019-01-07 + */ +@Configuration +public class QuartzConfig { + + /** + * 解决Job中注入Spring Bean为null的问题 + */ + @Component("quartzJobFactory") + public static class QuartzJobFactory extends AdaptableJobFactory { + + private final AutowireCapableBeanFactory capableBeanFactory; + + public QuartzJobFactory(AutowireCapableBeanFactory capableBeanFactory) { + this.capableBeanFactory = capableBeanFactory; + } + + @Override + protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { + //调用父类的方法,把Job注入到spring中 + Object jobInstance = super.createJobInstance(bundle); + capableBeanFactory.autowireBean(jobInstance); + return jobInstance; + } + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/domain/QuartzJob.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/domain/QuartzJob.java new file mode 100644 index 0000000..d4048fc --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/domain/QuartzJob.java @@ -0,0 +1,92 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.annotation.Query; +import me.zhengjie.base.BaseEntity; +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +@Getter +@Setter +@Entity +@Table(name = "sys_quartz_job") +public class QuartzJob extends BaseEntity implements Serializable { + + public static final String JOB_KEY = "JOB_KEY"; + + @Id + @Column(name = "job_id") + @NotNull(groups = {Update.class}) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + /** 任务编号 -雪花算法生成 */ + private Long taskNum; + + @ApiModelProperty(value = "类型 1.普通 2.影刀") + private Integer type = 1; + + @Transient + @ApiModelProperty(value = "用于子任务唯一标识", hidden = true) + private String uuid; + + @ApiModelProperty(value = "定时器名称") + private String jobName; + + @NotBlank + @ApiModelProperty(value = "Bean名称") + private String beanName; + + @NotBlank + @ApiModelProperty(value = "方法名称") + private String methodName; + + @ApiModelProperty(value = "参数") + private String params; + + @NotBlank + @ApiModelProperty(value = "cron表达式") + private String cronExpression; + + @ApiModelProperty(value = "状态,暂时或启动") + private Boolean isPause = false; + + @ApiModelProperty(value = "负责人") + private String personInCharge; + + @ApiModelProperty(value = "报警邮箱") + private String email; + + @ApiModelProperty(value = "子任务") + private String subTask; + + @ApiModelProperty(value = "失败后暂停") + private Boolean pauseAfterFailure; + + @NotBlank + @ApiModelProperty(value = "备注") + private String description; +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/domain/QuartzLog.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/domain/QuartzLog.java new file mode 100644 index 0000000..4dc510b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/domain/QuartzLog.java @@ -0,0 +1,70 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.hibernate.annotations.CreationTimestamp; +import javax.persistence.*; +import java.io.Serializable; +import java.sql.Timestamp; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +@Entity +@Data +@Table(name = "sys_quartz_log") +public class QuartzLog implements Serializable { + + @Id + @Column(name = "log_id") + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ApiModelProperty(value = "任务名称", hidden = true) + private String jobName; + + @ApiModelProperty(value = "类型 1.普通 2.影刀") + private Integer type = 1; + + @ApiModelProperty(value = "bean名称", hidden = true) + private String beanName; + + @ApiModelProperty(value = "方法名称", hidden = true) + private String methodName; + + @ApiModelProperty(value = "参数", hidden = true) + private String params; + + @ApiModelProperty(value = "cron表达式", hidden = true) + private String cronExpression; + + @ApiModelProperty(value = "状态", hidden = true) + private Boolean isSuccess; + + @ApiModelProperty(value = "异常详情", hidden = true) + private String exceptionDetail; + + @ApiModelProperty(value = "执行耗时", hidden = true) + private Long time; + + @CreationTimestamp + @ApiModelProperty(value = "创建时间", hidden = true) + private Timestamp createTime; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/repository/QuartzJobRepository.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/repository/QuartzJobRepository.java new file mode 100644 index 0000000..79b222b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/repository/QuartzJobRepository.java @@ -0,0 +1,34 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.repository; + +import me.zhengjie.modules.quartz.domain.QuartzJob; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import java.util.List; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +public interface QuartzJobRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 查询启用的任务 + * @return List + */ + List findByIsPauseIsFalse(); +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/repository/QuartzLogRepository.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/repository/QuartzLogRepository.java new file mode 100644 index 0000000..db724aa --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/repository/QuartzLogRepository.java @@ -0,0 +1,28 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.repository; + +import me.zhengjie.modules.quartz.domain.QuartzLog; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +public interface QuartzLogRepository extends JpaRepository, JpaSpecificationExecutor { + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/rest/QuartzJobController.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/rest/QuartzJobController.java new file mode 100644 index 0000000..7a4a3db --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/rest/QuartzJobController.java @@ -0,0 +1,127 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.Log; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.quartz.domain.QuartzJob; +import me.zhengjie.modules.quartz.service.QuartzJobService; +import me.zhengjie.modules.quartz.service.dto.JobQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/jobs") +@Api(tags = "系统:定时任务管理") +public class QuartzJobController { + + private static final String ENTITY_NAME = "quartzJob"; + private final QuartzJobService quartzJobService; + + @ApiOperation("查询定时任务") + @GetMapping + @PreAuthorize("@el.check('timing:list')") + public ResponseEntity query(JobQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(quartzJobService.queryAll(criteria,pageable), HttpStatus.OK); + } + + @ApiOperation("导出任务数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('timing:list')") + public void download(HttpServletResponse response, JobQueryCriteria criteria) throws IOException { + quartzJobService.download(quartzJobService.queryAll(criteria), response); + } + + @ApiOperation("导出日志数据") + @GetMapping(value = "/logs/download") + @PreAuthorize("@el.check('timing:list')") + public void downloadLog(HttpServletResponse response, JobQueryCriteria criteria) throws IOException { + quartzJobService.downloadLog(quartzJobService.queryAllLog(criteria), response); + } + + @ApiOperation("查询任务执行日志") + @GetMapping(value = "/logs") + @PreAuthorize("@el.check('timing:list')") + public ResponseEntity queryJobLog(JobQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(quartzJobService.queryAllLog(criteria,pageable), HttpStatus.OK); + } + + @Log("新增定时任务") + @ApiOperation("新增定时任务") + @PostMapping + @PreAuthorize("@el.check('timing:add')") + public ResponseEntity create(@Validated @RequestBody QuartzJob resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + quartzJobService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改定时任务") + @ApiOperation("修改定时任务") + @PutMapping + @PreAuthorize("@el.check('timing:edit')") + public ResponseEntity update(@Validated(QuartzJob.Update.class) @RequestBody QuartzJob resources){ + quartzJobService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("更改定时任务状态") + @ApiOperation("更改定时任务状态") + @PutMapping(value = "/{id}") + @PreAuthorize("@el.check('timing:edit')") + public ResponseEntity update(@PathVariable Long id){ + quartzJobService.updateIsPause(quartzJobService.findById(id)); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("执行定时任务") + @ApiOperation("执行定时任务") + @PutMapping(value = "/exec/{id}") + @PreAuthorize("@el.check('timing:edit')") + public ResponseEntity execution(@PathVariable Long id){ + quartzJobService.execution(quartzJobService.findById(id)); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除定时任务") + @ApiOperation("删除定时任务") + @DeleteMapping + @PreAuthorize("@el.check('timing:del')") + public ResponseEntity delete(@RequestBody Set ids){ + quartzJobService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/QuartzJobService.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/QuartzJobService.java new file mode 100644 index 0000000..7be008e --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/QuartzJobService.java @@ -0,0 +1,128 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.service; + +import me.zhengjie.modules.quartz.domain.QuartzJob; +import me.zhengjie.modules.quartz.domain.QuartzLog; +import me.zhengjie.modules.quartz.service.dto.JobQueryCriteria; +import org.springframework.data.domain.Pageable; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +public interface QuartzJobService { + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(JobQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部 + * @param criteria 条件 + * @return / + */ + List queryAll(JobQueryCriteria criteria); + + /** + * 查询全部 + * @return / + */ + void delAllLog(); + + /** + * 分页查询日志 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAllLog(JobQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部 + * @param criteria 条件 + * @return / + */ + List queryAllLog(JobQueryCriteria criteria); + + /** + * 创建 + * @param resources / + */ + void create(QuartzJob resources); + + /** + * 编辑 + * @param resources / + */ + void update(QuartzJob resources); + + /** + * 删除任务 + * @param ids / + */ + void delete(Set ids); + + /** + * 根据ID查询 + * @param id ID + * @return / + */ + QuartzJob findById(Long id); + + /** + * 更改定时任务状态 + * @param quartzJob / + */ + void updateIsPause(QuartzJob quartzJob); + + /** + * 立即执行定时任务 + * @param quartzJob / + */ + void execution(QuartzJob quartzJob); + + /** + * 导出定时任务 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; + + /** + * 导出定时任务日志 + * @param queryAllLog 待导出的数据 + * @param response / + * @throws IOException / + */ + void downloadLog(List queryAllLog, HttpServletResponse response) throws IOException; + + /** + * 执行子任务 + * @param tasks / + * @throws InterruptedException / + */ + void executionSubJob(String[] tasks) throws InterruptedException; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/SysQuartzJobService.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/SysQuartzJobService.java new file mode 100644 index 0000000..d2a58f1 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/SysQuartzJobService.java @@ -0,0 +1,77 @@ +package me.zhengjie.modules.quartz.service; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.SysQuartzJob; +import me.zhengjie.modules.group.dto.SysQuartzJobAddDTO; +import me.zhengjie.modules.group.dto.SysQuartzJobUpdateDTO; +import me.zhengjie.service.vo.SysQuartzJobListVO; +import me.zhengjie.utils.PageUtils; + +/** + * 定时任务(SysQuartzJob)表服务接口 + * + * @author zhw + * @since 2022-07-21 + */ +public interface SysQuartzJobService extends IService { + + PageUtils searchPageList(IPage page, Wrapper wrapper); + + /** + * 根据任务id修改任务运行状态 + * @param jobId + * @return boolean + */ + Boolean modifyJobStatus(Long jobId); + + /** + * 根据任务id修改任务信息 + * @param dto + * @return boolean + */ + Dto updateQuartzJobById(SysQuartzJobUpdateDTO dto); + + /** + * 根据任务id删除影刀任务 + * @param id + * @return boolean + */ + Boolean deleteQuartzJobById(Long id); + + /** + * 重新新建任务-为了任务失败做的 + * @param sysQuartzJob + * @return + */ + public Boolean reAddQuartzJob(SysQuartzJob sysQuartzJob); + + /** + * 新增影刀任务信息 + * @param dto + * @return boolean + */ + Dto addQuartzJob(SysQuartzJobAddDTO dto); + + /** + * 执行影刀任务信息 + * @param id + * @return boolean + */ + Boolean executionById(Long id); + + /** + * 根据刷单item拼装参数 + */ + String assemblyParamAccordingToItem(String params, String taskName, Long taskNum); + + /** + * 更加任务编号获取任务信息 + * @param taskNum + * @return + */ + SysQuartzJob getByTaskNum(String taskNum); +} + diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/dto/JobQueryCriteria.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/dto/JobQueryCriteria.java new file mode 100644 index 0000000..89d8070 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/dto/JobQueryCriteria.java @@ -0,0 +1,41 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.service.dto; + +import lombok.Data; +import me.zhengjie.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** + * @author Zheng Jie + * @date 2019-6-4 10:33:02 + */ +@Data +public class JobQueryCriteria { + + @Query(type = Query.Type.INNER_LIKE) + private String jobName; + + @Query + private Boolean isSuccess; + + @Query + private Integer type = 1; + + @Query(type = Query.Type.BETWEEN) + private List createTime; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/impl/QuartzJobServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/impl/QuartzJobServiceImpl.java new file mode 100644 index 0000000..35c6070 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/impl/QuartzJobServiceImpl.java @@ -0,0 +1,205 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.service.impl; + +import cn.hutool.core.lang.Snowflake; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import lombok.RequiredArgsConstructor; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.quartz.domain.QuartzJob; +import me.zhengjie.modules.quartz.domain.QuartzLog; +import me.zhengjie.modules.quartz.repository.QuartzJobRepository; +import me.zhengjie.modules.quartz.repository.QuartzLogRepository; +import me.zhengjie.modules.quartz.service.QuartzJobService; +import me.zhengjie.modules.quartz.service.dto.JobQueryCriteria; +import me.zhengjie.modules.quartz.utils.QuartzManage; +import me.zhengjie.utils.*; +import org.quartz.CronExpression; +import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +@RequiredArgsConstructor +@Service(value = "quartzJobService") +public class QuartzJobServiceImpl implements QuartzJobService { + + private final QuartzJobRepository quartzJobRepository; + private final QuartzLogRepository quartzLogRepository; + private final QuartzManage quartzManage; + private final RedisUtils redisUtils; + private final Snowflake snowflake; + + @Override + public Object queryAll(JobQueryCriteria criteria, Pageable pageable){ + return PageUtil.toPage(quartzJobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable)); + } + + @Override + public Object queryAllLog(JobQueryCriteria criteria, Pageable pageable){ + return PageUtil.toPage(quartzLogRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable)); + } + + @Override + public List queryAll(JobQueryCriteria criteria) { + return quartzJobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)); + } + + @Override + public void delAllLog() { + quartzLogRepository.deleteAll(); + } + + @Override + public List queryAllLog(JobQueryCriteria criteria) { + return quartzLogRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)); + } + + @Override + public QuartzJob findById(Long id) { + QuartzJob quartzJob = quartzJobRepository.findById(id).orElseGet(QuartzJob::new); + ValidationUtil.isNull(quartzJob.getId(),"QuartzJob","id",id); + return quartzJob; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(QuartzJob resources) { + if (!CronExpression.isValidExpression(resources.getCronExpression())){ + throw new BadRequestException("cron表达式格式错误"); + } + resources.setTaskNum(snowflake.nextId()); + resources = quartzJobRepository.save(resources); + quartzManage.addJob(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(QuartzJob resources) { + if (!CronExpression.isValidExpression(resources.getCronExpression())){ + throw new BadRequestException("cron表达式格式错误"); + } + if(StringUtils.isNotBlank(resources.getSubTask())){ + List tasks = Arrays.asList(resources.getSubTask().split("[,,]")); + if (tasks.contains(resources.getId().toString())) { + throw new BadRequestException("子任务中不能添加当前任务ID"); + } + } + resources = quartzJobRepository.save(resources); + quartzManage.updateJobCron(resources); + } + + @Override + public void updateIsPause(QuartzJob quartzJob) { + if (quartzJob.getIsPause()) { + quartzManage.resumeJob(quartzJob); + quartzJob.setIsPause(false); + } else { + quartzManage.pauseJob(quartzJob); + quartzJob.setIsPause(true); + } + quartzJobRepository.save(quartzJob); + } + + @Override + public void execution(QuartzJob quartzJob) { + quartzManage.runJobNow(quartzJob); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + for (Long id : ids) { + QuartzJob quartzJob = findById(id); + quartzManage.deleteJob(quartzJob); + quartzJobRepository.delete(quartzJob); + } + } + + @Async + @Override + @Transactional(rollbackFor = Exception.class) + public void executionSubJob(String[] tasks) throws InterruptedException { + for (String id : tasks) { + if (StrUtil.isBlank(id)) { + // 如果是手动清除子任务id,会出现id为空字符串的问题 + continue; + } + QuartzJob quartzJob = findById(Long.parseLong(id)); + // 执行任务 + String uuid = IdUtil.simpleUUID(); + quartzJob.setUuid(uuid); + // 执行任务 + execution(quartzJob); + // 获取执行状态,如果执行失败则停止后面的子任务执行 + Boolean result = (Boolean) redisUtils.get(uuid); + while (result == null) { + // 休眠5秒,再次获取子任务执行情况 + Thread.sleep(5000); + result = (Boolean) redisUtils.get(uuid); + } + if(!result){ + redisUtils.del(uuid); + break; + } + } + } + + @Override + public void download(List quartzJobs, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (QuartzJob quartzJob : quartzJobs) { + Map map = new LinkedHashMap<>(); + map.put("任务名称", quartzJob.getJobName()); + map.put("Bean名称", quartzJob.getBeanName()); + map.put("执行方法", quartzJob.getMethodName()); + map.put("参数", quartzJob.getParams()); + map.put("表达式", quartzJob.getCronExpression()); + map.put("状态", quartzJob.getIsPause() ? "暂停中" : "运行中"); + map.put("描述", quartzJob.getDescription()); + map.put("创建日期", quartzJob.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + @Override + public void downloadLog(List queryAllLog, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (QuartzLog quartzLog : queryAllLog) { + Map map = new LinkedHashMap<>(); + map.put("任务名称", quartzLog.getJobName()); + map.put("Bean名称", quartzLog.getBeanName()); + map.put("执行方法", quartzLog.getMethodName()); + map.put("参数", quartzLog.getParams()); + map.put("表达式", quartzLog.getCronExpression()); + map.put("异常详情", quartzLog.getExceptionDetail()); + map.put("耗时/毫秒", quartzLog.getTime()); + map.put("状态", quartzLog.getIsSuccess() ? "成功" : "失败"); + map.put("创建日期", quartzLog.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/impl/SysQuartzJobServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/impl/SysQuartzJobServiceImpl.java new file mode 100644 index 0000000..45b09bd --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/service/impl/SysQuartzJobServiceImpl.java @@ -0,0 +1,521 @@ +package me.zhengjie.modules.quartz.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import me.zhengjie.config.SystemConfig; +import me.zhengjie.dao.SysQuartzJobDao; +import me.zhengjie.dto.Dto; +import me.zhengjie.entity.*; +import me.zhengjie.entity.quartz.Boss; +import me.zhengjie.entity.quartz.Param; +import me.zhengjie.entity.quartz.Params; +import me.zhengjie.enums.*; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.group.dto.SysQuartzJobAddDTO; +import me.zhengjie.modules.group.dto.SysQuartzJobUpdateDTO; +import me.zhengjie.modules.quartz.domain.QuartzJob; +import me.zhengjie.modules.quartz.service.QuartzJobService; +import me.zhengjie.modules.quartz.service.SysQuartzJobService; +import me.zhengjie.modules.quartz.utils.QuartzManage; +import me.zhengjie.service.*; +import me.zhengjie.service.vo.CtBrowseDetailVO; +import me.zhengjie.service.vo.SysQuartzJobListVO; +import me.zhengjie.service.vo.dhaddcar.DhAddCarListVO; +import me.zhengjie.service.vo.dhaddcar.DhAddCarYdParamsVO; +import me.zhengjie.service.vo.dhcargood.DhCarGoodKeyVO; +import me.zhengjie.service.vo.dhcargood.DhCarGoodLinkVO; +import me.zhengjie.service.vo.dhcarorder.DhCarOrderParamsVO; +import me.zhengjie.utils.PageUtils; +import me.zhengjie.utils.StringUtils; +import org.quartz.CronExpression; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 定时任务(SysQuartzJob)表服务实现类 + * + * @author rch + * @since 2022-07-20 + */ +@Service +@RequiredArgsConstructor +public class SysQuartzJobServiceImpl extends ServiceImpl implements SysQuartzJobService { + + @Resource + private SysQuartzJobDao sysQuartzJobDao; + @Resource + private QuartzJobService quartzJobService; + @Resource + private CtApplyService ctApplyService; + @Resource + private CtClickFarmingService ctClickFarmingService; + @Resource + private DhAddCarService dhAddCarService; + @Resource + private DhAddCarOrderService dhAddCarOrderService; + @Resource + private CtClickOrderService ctClickOrderService; + @Resource + private CtBrowseService ctBrowseService; + private final QuartzManage quartzManage; + + @Override + public PageUtils searchPageList(IPage page, Wrapper wrapper) { + sysQuartzJobDao.searchPageList(page, wrapper); + return new PageUtils(page.getTotal(), page.getRecords()); + } + + @Override + public Boolean modifyJobStatus(Long jobId) { + SysQuartzJob sysQuartzJobIsExist = getById(jobId); + if (sysQuartzJobIsExist == null) { + return false; + } else { + QuartzJob quartzJob = new QuartzJob(); + BeanUtil.copyProperties(sysQuartzJobIsExist, quartzJob); + quartzJob.setId(sysQuartzJobIsExist.getJobId()); + + quartzJob.setType(TaskTypeEnum.SHADOW_KNIFE.value()); + SysQuartzJob updateSysQuartzJob = new SysQuartzJob(); + updateSysQuartzJob.setJobId(jobId); + + if (sysQuartzJobIsExist.getIsPause() == 1) { + quartzManage.resumeJob(quartzJob); + updateSysQuartzJob.setIsPause(0); + } else { + quartzManage.pauseJob(quartzJob); + updateSysQuartzJob.setIsPause(1); + } + return updateById(updateSysQuartzJob); + } + } + + @Override + public Dto updateQuartzJobById(SysQuartzJobUpdateDTO dto) { + SysQuartzJob sysQuartzJob = getById(dto.getJobId()); + if (sysQuartzJob == null) { + return Dto.getInstance(ErrorCodeEnum.ERROR_NOT_FIND_JOB); + } + if (!CronExpression.isValidExpression(dto.getCronExpression())) { + //hrow new BadRequestException("cron表达式格式错误"); + return Dto.returnErrorResult("cron表达式格式错误"); + } + if (StringUtils.isNotBlank(dto.getSubTask())) { + List tasks = Arrays.asList(dto.getSubTask().split("[,,]")); + if (tasks.contains(dto.getJobId().toString())) { + //throw new BadRequestException("子任务中不能添加当前任务ID"); + return Dto.returnErrorResult("子任务中不能添加当前任务ID"); + } + } + SysQuartzJob updateSysQuartzJob = new SysQuartzJob(); + + updateSysQuartzJob.setJobId(dto.getJobId()); + BeanUtil.copyProperties(dto, updateSysQuartzJob); + CtApply ctApply = ctApplyService.getById(dto.getApplyId()); + updateSysQuartzJob.setBeanName(ctApply.getTaskName()); + updateSysQuartzJob.setMethodName(ctApply.getMethodName()); + updateSysQuartzJob.setUpdateTime(DateUtil.now()); + + + QuartzJob quartzJob = new QuartzJob(); + BeanUtil.copyProperties(updateSysQuartzJob, quartzJob); + quartzJob.setId(dto.getJobId()); + quartzJob.setType(TaskTypeEnum.SHADOW_KNIFE.value()); + + quartzManage.updateJobCron(quartzJob); + return Dto.returnResult(updateById(updateSysQuartzJob)); + } + + + @Override + public Boolean deleteQuartzJobById(Long id) { + QuartzJob quartzJob = quartzJobService.findById(id); + quartzManage.deleteJob(quartzJob); + return removeById(id); + } + + @Override + public Dto addQuartzJob(SysQuartzJobAddDTO dto) { + if (!CronExpression.isValidExpression(dto.getCronExpression())) { + //throw new BadRequestException("cron表达式格式错误"); + return Dto.returnErrorResult("cron表达式格式错误"); + } + SysQuartzJob sysQuartzJob = new SysQuartzJob(); + BeanUtil.copyProperties(dto, sysQuartzJob); + ; + sysQuartzJob.setCreateTime(DateUtil.now()); + sysQuartzJob.setType(TaskTypeEnum.SHADOW_KNIFE.value()); + CtApply ctApply = ctApplyService.getById(dto.getApplyId()); + sysQuartzJob.setBeanName(ctApply.getTaskName()); + sysQuartzJob.setMethodName(ctApply.getMethodName()); + + QuartzJob quartzJob = new QuartzJob(); + quartzJob.setType(TaskTypeEnum.SHADOW_KNIFE.value()); + Boolean returnBoolean = save(sysQuartzJob); + if (returnBoolean) { + BeanUtil.copyProperties(sysQuartzJob, quartzJob); + quartzJob.setId(sysQuartzJob.getJobId()); + quartzManage.addJob(quartzJob); + } + //return returnBoolean; + return Dto.returnResult(returnBoolean); + } + + @Override + public Boolean reAddQuartzJob(SysQuartzJob sysQuartzJob) { + if (!CronExpression.isValidExpression(sysQuartzJob.getCronExpression())) { + throw new BadRequestException("cron表达式格式错误"); + } + sysQuartzJob.setCreateTime(DateUtil.now()); + QuartzJob quartzJob = new QuartzJob(); + quartzJob.setType(TaskTypeEnum.SHADOW_KNIFE.value()); + Boolean returnBoolean = save(sysQuartzJob); + if (returnBoolean) { + BeanUtil.copyProperties(sysQuartzJob, quartzJob); + quartzJob.setId(sysQuartzJob.getJobId()); + quartzManage.addJob(quartzJob); + } + return returnBoolean; + } + + @Override + public Boolean executionById(Long id) { + QuartzJob quartzJob = quartzJobService.findById(id); + quartzManage.runJobNow(quartzJob); + return true; + } + + @Override + public String assemblyParamAccordingToItem(String params, String taskName, Long taskNum) { + if (StringUtils.isEmpty(params) || StringUtils.isEmpty(taskName)) { + return null; + } + // 测试的第一个应用 刷单 拼装params + if (TaskInfoEnum.CLICK_FARMING.getTaskName().equals(taskName)) { + // 刷单 + Params paramsObj = JSONUtil.toBean(params, Params.class); + Boss bossObj = JSONUtil.toBean(params, Boss.class); + CtClickFarming ctClickFarming = ctClickFarmingService.getByIdLock(Long.valueOf(paramsObj.getParams())); + if (ObjectUtil.isEmpty(ctClickFarming)) { + return null; + // 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 5.待支付 + } else if (ClickFarmingStatusEnum.IN_EXECUTION.value().equals(ctClickFarming.getStatus()) || ClickFarmingStatusEnum.EXECUTION_SUCCESS.value().equals(ctClickFarming.getStatus())) { + return null; + } else { + // 关联查询 得到对应传值任务参数 不特殊处理统一返回好了,影刀脚本那边自行判断 + CtClickFarmYdParams ctClickFarmYdParams = ctClickFarmingService.getCtClickFarmYdParams(Long.valueOf(paramsObj.getParams())); + if (ObjectUtil.isEmpty(ctClickFarmYdParams)) { + log.error("根据刷单id关联查询相关信息空值异常!!!"); + return null; + } + List paramList = new ArrayList<>(); + Map maps = BeanUtil.beanToMap(ctClickFarmYdParams); + maps.entrySet().removeIf(entry -> entry.getValue() == null); + + for (Map.Entry map : maps.entrySet()) { + Param ydParam = new Param(); + ydParam.setName(map.getKey()); + ydParam.setValue(map.getValue().toString()); + paramList.add(ydParam); + } + + if (ObjectUtil.isNotEmpty(taskNum)) { + Param ydParam = new Param(); + ydParam.setName("taskNum"); + ydParam.setValue(taskNum.toString()); + paramList.add(ydParam); + } + + // 组装Params + bossObj.setParams(paramList); + return JSONUtil.toJsonStr(bossObj); + } + } else if (TaskInfoEnum.DH_ADD_CAR_FARMING.getTaskName().equals(taskName)) { + // 敦煌 加购 + Params paramsObj = JSONUtil.toBean(params, Params.class); + Boss bossObj = JSONUtil.toBean(params, Boss.class); + DhAddCar dhAddCar = dhAddCarService.getByIdLock(Long.valueOf(paramsObj.getParams())); + if (ObjectUtil.isEmpty(dhAddCar)) { + return null; + } else if (!ClickFarmingStatusEnum.TOBE_EXECUTION.value().equals(dhAddCar.getStatus()) && !ClickFarmingStatusEnum.EXECUTION_FAILE.value().equals(dhAddCar.getStatus())) { + return null; + } else { + // 关联查询 得到对应传值任务参数 不特殊处理统一返回好了,影刀脚本那边自行判断 + DhAddCarYdParamsVO dhAddCarYdParamsVO = dhAddCarService.getAddCarYdParams(Long.valueOf(paramsObj.getParams())); + if (ObjectUtil.isEmpty(dhAddCarYdParamsVO)) { + log.error("根据刷单id关联查询相关信息空值异常!!!"); + return null; + } + List paramList = new ArrayList<>(); + Map maps = BeanUtil.beanToMap(dhAddCarYdParamsVO); + maps.entrySet().removeIf(entry -> entry.getValue() == null); + + for (Map.Entry map : maps.entrySet()) { + Param ydParam = new Param(); + String value = null; + // 特殊处理 + if ("carGoodKeys".equals(map.getKey()) || "carGoodLinks".equals(map.getKey())) { + Object carGoodKeysObj = map.getValue(); + value = JSONUtil.parseArray(carGoodKeysObj).toString(); + } else { + value = map.getValue().toString(); + } + + ydParam.setName(map.getKey()); + ydParam.setValue(value); + paramList.add(ydParam); + } + + if (ObjectUtil.isNotEmpty(taskNum)) { + Param ydParam = new Param(); + ydParam.setName("taskNum"); + ydParam.setValue(taskNum.toString()); + paramList.add(ydParam); + } + + // 组装Params + bossObj.setParams(paramList); + return JSONUtil.toJsonStr(bossObj); + } + } else if (TaskInfoEnum.DH_ADD_CAR_CATCH_ORDER.getTaskName().equals(taskName)) { + // 敦煌 - 抓单 + Params paramsObj = JSONUtil.toBean(params, Params.class); + Boss bossObj = JSONUtil.toBean(params, Boss.class); + DhAddCar dhAddCar = dhAddCarService.getByIdLock(Long.valueOf(paramsObj.getParams())); + if (ObjectUtil.isEmpty(dhAddCar)) { + return null; + } else if (!DhAddCarStatusEnum.TO_BE_CATCH_ORDER.value().equals(dhAddCar.getStatus()) && !DhAddCarStatusEnum.CATCH_ORDER_FAILE.value().equals(dhAddCar.getStatus())) { + return null; + } else { + // 关联查询 得到对应传值任务参数 不特殊处理统一返回好了,影刀脚本那边自行判断 + DhAddCarYdParamsVO dhAddCarYdParamsVO = dhAddCarService.getAddCarYdParams(Long.valueOf(paramsObj.getParams())); + if (ObjectUtil.isEmpty(dhAddCarYdParamsVO)) { + log.error("根据刷单id关联查询相关信息空值异常!!!"); + return null; + } + List paramList = new ArrayList<>(); + Map maps = BeanUtil.beanToMap(dhAddCarYdParamsVO); + maps.entrySet().removeIf(entry -> entry.getValue() == null); + + for (Map.Entry map : maps.entrySet()) { + Param ydParam = new Param(); + String value = null; + // 特殊处理 + if ("carGoodKeys".equals(map.getKey()) || "carGoodLinks".equals(map.getKey())) { + Object carGoodKeysObj = map.getValue(); + value = JSONUtil.parseArray(carGoodKeysObj).toString(); + } else { + value = map.getValue().toString(); + } + + ydParam.setName(map.getKey()); + ydParam.setValue(value); + paramList.add(ydParam); + } + + if (ObjectUtil.isNotEmpty(taskNum)) { + Param ydParam = new Param(); + ydParam.setName("taskNum"); + ydParam.setValue(taskNum.toString()); + paramList.add(ydParam); + } + // 组装Params + bossObj.setParams(paramList); + return JSONUtil.toJsonStr(bossObj); + } + } else if (TaskInfoEnum.CLICK_FARMING_SUPPLE_MENY.getTaskName().equals(taskName)) { + // 补录 + Params paramsObj = JSONUtil.toBean(params, Params.class); + Boss bossObj = JSONUtil.toBean(params, Boss.class); + CtClickFarming ctClickFarming = ctClickFarmingService.getByIdLock(Long.valueOf(paramsObj.getParams())); + if (ObjectUtil.isEmpty(ctClickFarming)) { + return null; + // 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 5.待支付 + } else if (ClickFarmingStatusEnum.IN_EXECUTION.value().equals(ctClickFarming.getStatus()) || ClickFarmingStatusEnum.EXECUTION_SUCCESS.value().equals(ctClickFarming.getStatus())) { + return null; + } else { + CtClickFarmYdParams ctClickFarmYdParams = ctClickFarmingService.getCtClickFarmYdParams(Long.valueOf(paramsObj.getParams())); + if (ObjectUtil.isEmpty(ctClickFarmYdParams)) { + log.error("根据刷单id关联查询相关信息空值异常!!!"); + return null; + } + CtClickFarmSupplyMentYdParams ctClickFarmSupplyMentYdParams = new CtClickFarmSupplyMentYdParams(); + BeanUtil.copyProperties(ctClickFarmYdParams, ctClickFarmSupplyMentYdParams); + + List paramList = new ArrayList<>(); + Map maps = BeanUtil.beanToMap(ctClickFarmSupplyMentYdParams); + maps.entrySet().removeIf(entry -> entry.getValue() == null); + for (Map.Entry map : maps.entrySet()) { + Param ydParam = new Param(); + ydParam.setName(map.getKey()); + ydParam.setValue(map.getValue().toString()); + paramList.add(ydParam); + } + + // 组装Params + bossObj.setParams(paramList); + return JSONUtil.toJsonStr(bossObj); + } + } else if (TaskInfoEnum.WELL_RECEIVED.getTaskName().equals(taskName)) { + // 速卖通好评 + Params paramsObj = JSONUtil.toBean(params, Params.class); + Boss bossObj = JSONUtil.toBean(params, Boss.class); + CtClickOrder ctClickOrder = ctClickOrderService.getByIdLock(Long.valueOf(paramsObj.getParams())); + if (ObjectUtil.isEmpty(ctClickOrder)) { + return null; + // 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 5.待支付 + } else if (ClickOrderStatusEnum.IN_EXECUTION.value().equals(ctClickOrder.getStatus()) || ClickFarmingStatusEnum.EXECUTION_SUCCESS.value().equals(ctClickOrder.getStatus())) { + return null; + } else { + CtClickOrderYdParams ctClickOrderYdParams = new CtClickOrderYdParams(); + CtClickFarmingOrderInfo ctClickFarmingOrderInfo = ctClickOrderService.getClickFarmOrderById(Long.valueOf(paramsObj.getParams())); + if (ObjectUtil.isEmpty(ctClickFarmingOrderInfo)) { + log.error("根据刷单id关联查询相关信息空值异常!!!"); + return null; + } + BeanUtil.copyProperties(ctClickFarmingOrderInfo, ctClickOrderYdParams); + String paths = joinPath(ctClickOrderYdParams.getPaths()); + if (ObjectUtil.isNotEmpty(paths)) { + ctClickOrderYdParams.setPaths(paths); + } + List paramList = new ArrayList<>(); + Map maps = BeanUtil.beanToMap(ctClickOrderYdParams); + maps.entrySet().removeIf(entry -> entry.getValue() == null); + + for (Map.Entry map : maps.entrySet()) { + Param ydParam = new Param(); + ydParam.setName(map.getKey()); + ydParam.setValue(map.getValue().toString()); + paramList.add(ydParam); + } + + // 组装Params + bossObj.setParams(paramList); + return JSONUtil.toJsonStr(bossObj); + } + } else if (TaskInfoEnum.DH_WELL_RECEIVED.getTaskName().equals(taskName)) { + // TODO 敦煌好评 + Params paramsObj = JSONUtil.toBean(params, Params.class); + Boss bossObj = JSONUtil.toBean(params, Boss.class); + DhAddCarOrder dhAddCarOrder = dhAddCarOrderService.getByIdLock(Long.valueOf(paramsObj.getParams())); + if (ObjectUtil.isEmpty(dhAddCarOrder)) { + return null; + // 状态 1.抓单成功才允许 好评 + } else if (!ClickOrderStatusEnum.TOBE_EXECUTION.value().equals(dhAddCarOrder.getStatus()) && !ClickOrderStatusEnum.EXECUTION_FAILE.value().equals(dhAddCarOrder.getStatus())) { + return null; + } else { + + // TODO 拼装好评数据 + DhCarOrderParamsVO dhCarOrderParamsVO = dhAddCarOrderService.getYdParams(Long.valueOf(paramsObj.getParams())); + if (ObjectUtil.isEmpty(dhCarOrderParamsVO)) { + log.error("根据刷单id关联查询相关信息空值异常!!!"); + return null; + } + joinImagePath(dhCarOrderParamsVO); + List paramList = new ArrayList<>(); + Map maps = BeanUtil.beanToMap(dhCarOrderParamsVO); + maps.entrySet().removeIf(entry -> entry.getValue() == null); + + for (Map.Entry map : maps.entrySet()) { + Param ydParam = new Param(); + String value = null; + // 特殊处理 + if ("carGoodKeys".equals(map.getKey()) || "carGoodLinks".equals(map.getKey())) { + Object carGoodKeysObj = map.getValue(); + value = JSONUtil.parseArray(carGoodKeysObj).toString(); + } else { + value = map.getValue().toString(); + } + + ydParam.setName(map.getKey()); + ydParam.setValue(value); + paramList.add(ydParam); + } + + // 组装Params + bossObj.setParams(paramList); + return JSONUtil.toJsonStr(bossObj); + } + } else if (TaskInfoEnum.BROWSE.getTaskName().equals(taskName)) { + // 浏览收藏 + Params paramsObj = JSONUtil.toBean(params, Params.class); + Boss bossObj = JSONUtil.toBean(params, Boss.class); + CtBrowse ctBrowse = ctBrowseService.getByIdLock(Long.valueOf(paramsObj.getParams())); + if (ObjectUtil.isEmpty(ctBrowse)) { + return null; + // 状态 1.待执行 2.执行中 3.执行成功 4.执行失败 5.待支付 + } else if (ClickOrderStatusEnum.IN_EXECUTION.value().equals(ctBrowse.getStatus()) || ClickFarmingStatusEnum.EXECUTION_SUCCESS.value().equals(ctBrowse.getStatus())) { + return null; + } else { + // TODO 好评浏览 待修改 + CtBrowseYdParams ctBrowseYdParams = new CtBrowseYdParams(); + CtBrowseDetailVO ctBrowseDetailVO = ctBrowseService.getBrowseDetailById(Long.valueOf(paramsObj.getParams())); + BeanUtil.copyProperties(ctBrowseDetailVO, ctBrowseYdParams); + List paramList = new ArrayList<>(); + Map maps = BeanUtil.beanToMap(ctBrowseYdParams); + maps.entrySet().removeIf(entry -> entry.getValue() == null); + + for (Map.Entry map : maps.entrySet()) { + Param ydParam = new Param(); + ydParam.setName(map.getKey()); + ydParam.setValue(map.getValue().toString()); + paramList.add(ydParam); + } + + // 组装Params + bossObj.setParams(paramList); + return JSONUtil.toJsonStr(bossObj); + } + } else { + return null; + } + } + + private void joinImagePath(DhCarOrderParamsVO dhCarOrderParamsVO) { + if (ParamsTypeEnum.KEY_WORD.eqValue(dhCarOrderParamsVO.getParamsType()) && ObjectUtil.isNotEmpty(dhCarOrderParamsVO.getCarGoodKeys())) { + for (DhCarGoodKeyVO dhCarGoodKeyVO:dhCarOrderParamsVO.getCarGoodKeys()) { + String paths = dhCarGoodKeyVO.getPaths(); + dhCarGoodKeyVO.setPaths(joinPath(paths)); + } + } else if (ParamsTypeEnum.LINK.eqValue(dhCarOrderParamsVO.getParamsType()) && ObjectUtil.isNotEmpty(dhCarOrderParamsVO.getCarGoodLinks())) { + for (DhCarGoodLinkVO dhCarGoodLinkVO:dhCarOrderParamsVO.getCarGoodLinks()) { + String paths = dhCarGoodLinkVO.getPaths(); + dhCarGoodLinkVO.setPaths(joinPath(paths)); + } + } else { + return ; + } + } + + /** + * 拼接域名 + * @param paths + * @return + */ + private String joinPath(String paths) { + if (ObjectUtil.isEmpty(paths)) { + return null; + } + List pathList = Arrays.asList(paths.split(",")); + return pathList.stream().map(s -> s = SystemConfig.FILE_VISIT_ADDR + s).collect(Collectors.joining(",")); + } + + @Override + public SysQuartzJob getByTaskNum(String taskNum) { + return sysQuartzJobDao.getByTaskNum(taskNum); + } +} + diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/BossTask.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/BossTask.java new file mode 100644 index 0000000..85c0202 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/BossTask.java @@ -0,0 +1,51 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.task; + +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.entity.quartz.Boss; +import me.zhengjie.service.YdQuartzService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 测试用-Boss查询岗位 + * @author rch + * @date 2022-07-23 + */ +@Slf4j +@Component +public class BossTask { + + @Resource + private YdQuartzService ydQuartzService; + + public void run(String str) throws Exception { + Boss boss = JSONUtil.toBean(str, Boss.class); + String REBOT_KEY = PublicConstant.getRebotKeyPrefix(boss.getAccountName()); + ydQuartzService.executeOnLock(REBOT_KEY, 1, 1, callBack -> { + try { + return ydQuartzService.exec(str); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } +} + diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/BossTask22.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/BossTask22.java new file mode 100644 index 0000000..4adf48b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/BossTask22.java @@ -0,0 +1,165 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.task; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.config.YdApiProperties; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.entity.CtRebot; +import me.zhengjie.entity.quartz.Boss; +import me.zhengjie.entity.quartz.RebotStatu; +import me.zhengjie.entity.quartz.RebotStatuReturn; +import me.zhengjie.entity.quartz.SecreInfo; +import me.zhengjie.enums.YesOrNoEnum; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.service.CtRebotService; +import me.zhengjie.service.redission.LockCallBack; +import me.zhengjie.utils.HttpClientUtil; +import me.zhengjie.utils.RedissonUtil; +import org.redisson.api.RLock; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * 测试用-Boss查询岗位 + * @author rch + * @date 2022-07-23 + */ +@Slf4j +@Component +public class BossTask22 { + + @Resource + private CtRebotService ctRebotService; + @Resource + private RedissonUtil redissonUtil; + + public final static String REBOT_STATU = "https://api.winrobot360.com/oapi/dispatch/v2/client/query"; + public final static String GET_SECRET = "https://api.winrobot360.com/oapi/token/v2/token/create"; + public final static String STAT_JOB_URL = "https://api.winrobot360.com/oapi/dispatch/v2/job/start"; + + // 测试保证指执行一次 + public static Integer number = 0; + + public void run(){ + try { + Thread.sleep(5000); + log.info("run 执行成功====time:" + DateUtil.now()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + log.info("run---end!"); + } + + public void run2(String str){ + + number ++; + Boss boss = JSONUtil.toBean(str, Boss.class); + String REBOT_KEY = PublicConstant.getRebotKeyPrefix(boss.getAccountName()); + try { + executeOnLock(REBOT_KEY, 1, 1, callBack -> exec(str)); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public void run1(){ + log.info("run2 执行成功"); + } + + Object executeOnLock(String lockKey, long time, long timeout, LockCallBack callBack) throws BadRequestException,InterruptedException { + RLock lock = redissonUtil.getRLock(lockKey); + String currentTime = me.zhengjie.utils.DateUtil.getCurrentTime(); + try { + log.info(currentTime+" 获取锁============= {}",lockKey); + if (lock.tryLock(time, timeout, TimeUnit.SECONDS)) { + System.out.println(" run2 ====== lock success"); + return callBack.execute(true); + } else { + System.out.println(" run2 ====== lock fail "); + throw new BadRequestException(" run2 ====== lock fail "); + } + } catch (InterruptedException e) { + throw e; + } finally { + lock.unlock(); + log.info(currentTime+" 释放锁============= {}",lockKey); + } + } + + public Boolean exec(String str) { + Boss boss = JSONUtil.toBean(str, Boss.class); + // 1.根据设备id获取设备信息 for update + CtRebot ctRebot = ctRebotService.getByAccountNameLock(boss.getAccountName()); + System.out.println("run2================================"); + System.out.println(JSONUtil.toJsonStr(ctRebot)); + if (ObjectUtil.isEmpty(ctRebot) || !YesOrNoEnum.NO.eqValue(ctRebot.getStatus())) { + // 有问题 不执行 + log.info("run2 执行成功 - 结束了,设备信息问题,参数为: {}" + str); + return false; + } + + // token + Map params = new HashMap<>(16); + params.put("accessKeyId", YdApiProperties.ACCESS_KEY_ID); + params.put("accessKeySecret", YdApiProperties.ACCESS_KEY_SECRET); + String secretStr = HttpClientUtil.getHttp(GET_SECRET, params); + SecreInfo secreInfo = JSONUtil.toBean(secretStr, SecreInfo.class); + if (!secreInfo.getSuccess()) { + log.info("=========鉴权异常=========="); + return false; + } + String token = secreInfo.getData().getAccessToken(); + Map headers = new HashMap<>(16); + headers.put("Accept", "application/json"); + headers.put("Content-Type", "application/json;charset=utf-8"); + headers.put("authorization", "Bearer " + token); + + // 判断是否在线 + RebotStatu rebotStatu = new RebotStatu(); + rebotStatu.setAccountName(ctRebot.getAccountName()); + rebotStatu.setRobotClientUuid(ctRebot.getRobotClientUuid()); + String returnStr = HttpClientUtil.postJson(REBOT_STATU, headers, JSONUtil.toJsonStr(rebotStatu), "utf-8"); + RebotStatuReturn rebotStatuReturn = JSONUtil.toBean(returnStr, RebotStatuReturn.class); + if ("offline".equals(rebotStatuReturn.getData().getStatus())) { + log.info("=======设备不在线====="); + return false; + } + + // 修改机器人状态 + CtRebot updateCtRebot = new CtRebot(); + updateCtRebot.setId(ctRebot.getId()); + updateCtRebot.setStatus(YesOrNoEnum.YES.value()); + Boolean resultBoolean = ctRebotService.updateById(updateCtRebot); + if (resultBoolean) { + String returnJobStr = HttpClientUtil.postJson(STAT_JOB_URL, headers, JSONUtil.toJsonStr(boss), "utf-8"); + log.info("run2 执行成功,返回结果为: {}" + returnJobStr); + } else { + log.info("run2 执行成功。 但是修改设备状态失败----- 此处该预警"); + } + return true; + } +} + + diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/BrowseTask.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/BrowseTask.java new file mode 100644 index 0000000..9ca72aa --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/BrowseTask.java @@ -0,0 +1,54 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.task; + +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.entity.quartz.Boss; +import me.zhengjie.service.YdQuartzService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 浏览收藏任务 + * @author rch + * @date 2022-11-04 + */ +@Slf4j +@Component +public class BrowseTask { + + @Resource + private YdQuartzService ydQuartzService; + + public void run(String str) throws Exception { + System.out.println("================================BrowseTask=========================1"); + Boss boss = JSONUtil.toBean(str, Boss.class); + String REBOT_KEY = PublicConstant.getRebotKeyPrefix(boss.getAccountName()); + System.out.println("================================BrowseTask=========================2"); + ydQuartzService.executeOnLock(REBOT_KEY, 1, 1, callBack -> { + try { + System.out.println("================================BrowseTask=========================3"); + return ydQuartzService.browseTaskExec(str); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } +} + diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/ClickFarmSuppleMentTask.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/ClickFarmSuppleMentTask.java new file mode 100644 index 0000000..654079b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/ClickFarmSuppleMentTask.java @@ -0,0 +1,54 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.task; + +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.entity.quartz.Boss; +import me.zhengjie.service.YdQuartzService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 刷单补录任务 + * @author rch + * @date 2022-10-17 + */ +@Slf4j +@Component +public class ClickFarmSuppleMentTask { + + @Resource + private YdQuartzService ydQuartzService; + + public void run(String str) throws Exception { + System.out.println("================================ClickFarmSuppleMentTask=========================1"); + Boss boss = JSONUtil.toBean(str, Boss.class); + String REBOT_KEY = PublicConstant.getRebotKeyPrefix(boss.getAccountName()); + System.out.println("================================ClickFarmSuppleMentTask=========================2"); + ydQuartzService.executeOnLock(REBOT_KEY, 1, 1, callBack -> { + try { + System.out.println("================================ClickFarmSuppleMentTask=========================3"); + return ydQuartzService.clickFarmSuppleMentExec(str); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } +} + diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/ClickFarmTask.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/ClickFarmTask.java new file mode 100644 index 0000000..701e025 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/ClickFarmTask.java @@ -0,0 +1,54 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.task; + +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.entity.quartz.Boss; +import me.zhengjie.service.YdQuartzService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 刷单任务 + * @author rch + * @date 2022-08-16 + */ +@Slf4j +@Component +public class ClickFarmTask { + + @Resource + private YdQuartzService ydQuartzService; + + public void run(String str) throws Exception { + System.out.println("================================ClickFarmTask=========================1"); + Boss boss = JSONUtil.toBean(str, Boss.class); + String REBOT_KEY = PublicConstant.getRebotKeyPrefix(boss.getAccountName()); + System.out.println("================================ClickFarmTask=========================2"); + ydQuartzService.executeOnLock(REBOT_KEY, 1, 1, callBack -> { + try { + System.out.println("================================ClickFarmTask=========================3"); + return ydQuartzService.clickFarmExec(str); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } +} + diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/DhAddCarTask.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/DhAddCarTask.java new file mode 100644 index 0000000..d6f1518 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/DhAddCarTask.java @@ -0,0 +1,54 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.task; + +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.entity.quartz.Boss; +import me.zhengjie.service.YdQuartzService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 敦煌-加购 + * @author rch + * @date 2022-11-14 + */ +@Slf4j +@Component +public class DhAddCarTask { + + @Resource + private YdQuartzService ydQuartzService; + + public void run(String str) throws Exception { + System.out.println("================================ClickFarmTask=========================1"); + Boss boss = JSONUtil.toBean(str, Boss.class); + String REBOT_KEY = PublicConstant.getRebotKeyPrefix(boss.getAccountName()); + System.out.println("================================ClickFarmTask=========================2"); + ydQuartzService.executeOnLock(REBOT_KEY, 1, 1, callBack -> { + try { + System.out.println("================================ClickFarmTask=========================3"); + return ydQuartzService.addCarExec(str); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } +} + diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/DhCatchOrderTask.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/DhCatchOrderTask.java new file mode 100644 index 0000000..492a6ac --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/DhCatchOrderTask.java @@ -0,0 +1,54 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.task; + +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.entity.quartz.Boss; +import me.zhengjie.service.YdQuartzService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 敦煌-加购抓单任务 + * @author rch + * @date 2022-08-16 + */ +@Slf4j +@Component +public class DhCatchOrderTask { + + @Resource + private YdQuartzService ydQuartzService; + + public void run(String str) throws Exception { + System.out.println("================================DhCatchOrderTask=========================1"); + Boss boss = JSONUtil.toBean(str, Boss.class); + String REBOT_KEY = PublicConstant.getRebotKeyPrefix(boss.getAccountName()); + System.out.println("================================DhCatchOrderTask=========================2"); + ydQuartzService.executeOnLock(REBOT_KEY, 1, 1, callBack -> { + try { + System.out.println("================================DhCatchOrderTask=========================3"); + return ydQuartzService.catchOrderExec(str); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } +} + diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/DhPayTask.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/DhPayTask.java new file mode 100644 index 0000000..6a44236 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/DhPayTask.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.task; + +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.service.CtDhPayService; +import me.zhengjie.service.CtOrderService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 敦煌 支付 定时器 + * 计划 每10s 执行一次 -串行 + * @author rch + * @date 2022-07-28 + */ +@Slf4j +@Component +public class DhPayTask { + + @Resource + private CtDhPayService ctDhPayService; + + public void dhPayTaskRun(){ + try { + ctDhPayService.toPay(); + log.info("敦煌 支付 定时器---DhPayTask---dhPayTaskRun---执行成功"); + } catch (Exception e) { + e.printStackTrace(); + } + log.info("run---end!"); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/DhWellReceivedTask.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/DhWellReceivedTask.java new file mode 100644 index 0000000..79baee7 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/DhWellReceivedTask.java @@ -0,0 +1,54 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.task; + +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.entity.quartz.Boss; +import me.zhengjie.service.YdQuartzService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 敦煌-好评 + * @author rch + * @date 2022-11-14 + */ +@Slf4j +@Component +public class DhWellReceivedTask { + + @Resource + private YdQuartzService ydQuartzService; + + public void run(String str) throws Exception { + System.out.println("================================DhWellReceivedTask=========================1"); + Boss boss = JSONUtil.toBean(str, Boss.class); + String REBOT_KEY = PublicConstant.getRebotKeyPrefix(boss.getAccountName()); + System.out.println("================================DhWellReceivedTask=========================2"); + ydQuartzService.executeOnLock(REBOT_KEY, 1, 1, callBack -> { + try { + System.out.println("================================DhWellReceivedTask=========================3"); + return ydQuartzService.dhWellReceivedExec(str); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } +} + diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/ExcelToOrderTask.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/ExcelToOrderTask.java new file mode 100644 index 0000000..6ce201d --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/ExcelToOrderTask.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.task; + +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.service.CtOrderService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * Excel 数据转换存储到订单表里 Order 一对多 + * 计划 每10s 执行一次 -串行 + * @author rch + * @date 2022-06-23 + */ +@Slf4j +@Component +public class ExcelToOrderTask { + + @Resource + private CtOrderService ctOrderService; + + public void excelToOrderRun(){ + try { + ctOrderService.excelToOrder(); + log.info("Excel 数据转换存储到订单表里 Order---ExcelToOrderTask---excelToOrderRun---执行成功"); + } catch (Exception e) { + e.printStackTrace(); + } + log.info("run---end!"); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/ExcelmportTask.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/ExcelmportTask.java new file mode 100644 index 0000000..79e5068 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/ExcelmportTask.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.task; + +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.service.CtExcelImportInfoService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * Excel 数据导入到Mysql定时器 + * 计划 每10s 执行一次 -串行 + * @author rch + * @date 2022-06-23 + */ +@Slf4j +@Component +public class ExcelmportTask { + + @Resource + private CtExcelImportInfoService ctExcelImportInfoService; + + public void importRun(){ + try { + ctExcelImportInfoService.importExcel(); + log.info("Excel数据导入到Mysql定时器---ExcelmportTask---importRun---执行成功"); + } catch (Exception e) { + e.printStackTrace(); + } + log.info("run---end!"); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/OrderToPayTask.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/OrderToPayTask.java new file mode 100644 index 0000000..e62c8bd --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/OrderToPayTask.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.task; + +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.service.CtOrderService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 订单表里Order支付 定时器 + * 计划 每8s 执行一次 -串行 + * @author rch + * @date 2022-06-23 + */ +@Slf4j +@Component +public class OrderToPayTask { + + @Resource + private CtOrderService ctOrderService; + + public void orderToPayRun(){ + try { + ctOrderService.toPay(); + log.info("订单表里Order支付---OrderToPayTask---orderToPayRun---执行成功"); + } catch (Exception e) { + e.printStackTrace(); + } + log.info("run---end!"); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/RebotStatusTask.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/RebotStatusTask.java new file mode 100644 index 0000000..6266f5e --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/RebotStatusTask.java @@ -0,0 +1,95 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.task; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.config.YdApiProperties; +import me.zhengjie.constant.Constants; +import me.zhengjie.entity.CtRebot; +import me.zhengjie.entity.quartz.RebotStatu; +import me.zhengjie.entity.quartz.RebotStatuReturn; +import me.zhengjie.entity.quartz.SecreInfo; +import me.zhengjie.enums.CtReboteStatusEnum; +import me.zhengjie.enums.RobotStatusEnum; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.service.CtRebotService; +import me.zhengjie.utils.HttpClientUtil; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 机器人状态定时检测 + * @author rch + * @date 2022-08-06 + */ +@Slf4j +@Component +public class RebotStatusTask { + + @Resource + private CtRebotService ctRebotService; + + /** + * 计划20s执行一次 等到真的脚本写好了,就多点时间根据实际情况 + */ + public void run(){ + try { + // TODO 获取占用状态的机器人信息 然后定时调用接口 根据结果修改机器人状态 + QueryWrapper ctRebotQueryWrapper = new QueryWrapper<>(); + ctRebotQueryWrapper.eq("status", CtReboteStatusEnum.OCCUPY.value()); + + List ctRebotList = ctRebotService.list(ctRebotQueryWrapper); + + // token + Map params = new HashMap<>(16); + params.put("accessKeyId", YdApiProperties.ACCESS_KEY_ID); + params.put("accessKeySecret", YdApiProperties.ACCESS_KEY_SECRET); + SecreInfo secreInfo = JSONUtil.toBean(HttpClientUtil.getHttp(Constants.GET_SECRET, params), SecreInfo.class); + if (!secreInfo.getSuccess()) { + log.info("=========鉴权异常=========="); + throw new BadRequestException("请求影刀鉴权异常!"); + } + String token = secreInfo.getData().getAccessToken(); + Map headers = new HashMap<>(16); + headers.put("Accept", "application/json"); + headers.put("Content-Type", "application/json;charset=utf-8"); + headers.put("authorization", "Bearer " + token); + for (CtRebot ctRebot:ctRebotList) { + // 判断是否在线 + RebotStatu rebotStatu = new RebotStatu(ctRebot.getRobotClientUuid(), ctRebot.getAccountName()); + String returnStr = HttpClientUtil.postJson(Constants.REBOT_STATU, headers, JSONUtil.toJsonStr(rebotStatu), "utf-8"); + RebotStatuReturn rebotStatuReturn = JSONUtil.toBean(returnStr, RebotStatuReturn.class); + + if (ObjectUtil.isNotEmpty(rebotStatuReturn.getData()) && RobotStatusEnum.IDLE.value().equals(rebotStatuReturn.getData().getStatus())) { + Boolean result = ctRebotService.updateNewStatusByOldStatus(ctRebot.getId(), CtReboteStatusEnum.UNOCCUPIED.value(), ctRebot.getStatus()); + log.info("=======修改设备空闲状态=====ctRebot:{} --oldStatus:{}, ---newStatus{} --result:{}", JSONUtil.toJsonStr(ctRebot), ctRebot.getStatus(), CtReboteStatusEnum.UNOCCUPIED.value(), result); + } + } + + log.info("run 执行成功====time:" + DateUtil.now()); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/TestTask.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/TestTask.java new file mode 100644 index 0000000..5ec4a14 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/TestTask.java @@ -0,0 +1,49 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.task; + +import cn.hutool.core.date.DateUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 测试用 + * @author Zheng Jie + * @date 2019-01-08 + */ +@Slf4j +@Component +public class TestTask { + + public void run(){ + try { + Thread.sleep(5000); + log.info("run 执行成功====time:" + DateUtil.now()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + log.info("run---end!"); + } + + public void run1(String str){ + log.info("run1 执行成功,参数为: {}" + str); + } + + public void run2(){ + log.info("run2 执行成功"); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/WellReceivedTask.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/WellReceivedTask.java new file mode 100644 index 0000000..eaab091 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/task/WellReceivedTask.java @@ -0,0 +1,55 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.task; + +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.constant.PublicConstant; +import me.zhengjie.entity.quartz.Boss; +import me.zhengjie.service.YdQuartzService; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; + +/** + * 刷单任务 + * @author rch + * @date 2022-10-17 + */ +@Slf4j +@Component +public class WellReceivedTask { + + @Resource + private YdQuartzService ydQuartzService; + + public void run(String str) throws Exception { + System.out.println("================================WellReceivedTask=========================1"); + Boss boss = JSONUtil.toBean(str, Boss.class); + String REBOT_KEY = PublicConstant.getRebotKeyPrefix(boss.getAccountName()); + System.out.println("================================WellReceivedTask=========================2"); + ydQuartzService.executeOnLock(REBOT_KEY, 1, 1, callBack -> { + try { + System.out.println("================================WellReceivedTask=========================3"); + return ydQuartzService.wellReceivedExec(str); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } +} + diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/utils/ExecutionJob.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/utils/ExecutionJob.java new file mode 100644 index 0000000..267f20b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/utils/ExecutionJob.java @@ -0,0 +1,140 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.utils; + +import cn.hutool.extra.template.Template; +import cn.hutool.extra.template.TemplateConfig; +import cn.hutool.extra.template.TemplateEngine; +import cn.hutool.extra.template.TemplateUtil; +import me.zhengjie.config.thread.ThreadPoolExecutorUtil; +import me.zhengjie.domain.vo.EmailVo; +import me.zhengjie.modules.quartz.domain.QuartzJob; +import me.zhengjie.modules.quartz.domain.QuartzLog; +import me.zhengjie.modules.quartz.repository.QuartzLogRepository; +import me.zhengjie.modules.quartz.service.QuartzJobService; +import me.zhengjie.service.EmailService; +import me.zhengjie.utils.RedisUtils; +import me.zhengjie.utils.SpringContextHolder; +import me.zhengjie.utils.StringUtils; +import me.zhengjie.utils.ThrowableUtil; +import org.quartz.DisallowConcurrentExecution; +import org.quartz.JobExecutionContext; +import org.springframework.scheduling.quartz.QuartzJobBean; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Future; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * 参考人人开源,https://gitee.com/renrenio/renren-security + * @author / + * @date 2019-01-07 + */ +//@Async +@DisallowConcurrentExecution +public class ExecutionJob extends QuartzJobBean { + + /** 该处仅供参考 */ + private final static ThreadPoolExecutor EXECUTOR = ThreadPoolExecutorUtil.getPoll(); + + @Override + public void executeInternal(JobExecutionContext context) { + QuartzJob quartzJob = (QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY); + // 获取spring bean + QuartzLogRepository quartzLogRepository = SpringContextHolder.getBean(QuartzLogRepository.class); + QuartzJobService quartzJobService = SpringContextHolder.getBean(QuartzJobService.class); + RedisUtils redisUtils = SpringContextHolder.getBean(RedisUtils.class); + + String uuid = quartzJob.getUuid(); + + QuartzLog log = new QuartzLog(); + log.setJobName(quartzJob.getJobName()); + log.setBeanName(quartzJob.getBeanName()); + log.setMethodName(quartzJob.getMethodName()); + log.setParams(quartzJob.getParams()); + log.setType(quartzJob.getType()); + long startTime = System.currentTimeMillis(); + log.setCronExpression(quartzJob.getCronExpression()); + try { + // 执行任务 + System.out.println("--------------------------------------------------------------"); + System.out.println("任务开始执行,任务名称:" + quartzJob.getJobName()); + QuartzRunnable task = new QuartzRunnable(quartzJob.getBeanName(), quartzJob.getMethodName(), + quartzJob.getParams()); + Future future = EXECUTOR.submit(task); + future.get(); + long times = System.currentTimeMillis() - startTime; + log.setTime(times); + if(StringUtils.isNotBlank(uuid)) { + redisUtils.set(uuid, true); + } + // 任务状态 + log.setIsSuccess(true); + System.out.println("任务执行完毕,任务名称:" + quartzJob.getJobName() + ", 执行时间:" + times + "毫秒"); + System.out.println("--------------------------------------------------------------"); + // 判断是否存在子任务 + if(StringUtils.isNotBlank(quartzJob.getSubTask())){ + String[] tasks = quartzJob.getSubTask().split("[,,]"); + // 执行子任务 + quartzJobService.executionSubJob(tasks); + } + } catch (Exception e) { + if(StringUtils.isNotBlank(uuid)) { + redisUtils.set(uuid, false); + } + System.out.println("任务执行失败,任务名称:" + quartzJob.getJobName()); + System.out.println("--------------------------------------------------------------"); + long times = System.currentTimeMillis() - startTime; + log.setTime(times); + // 任务状态 0:成功 1:失败 + log.setIsSuccess(false); + log.setExceptionDetail(ThrowableUtil.getStackTrace(e)); + // 任务如果失败了则暂停 + if(quartzJob.getPauseAfterFailure() != null && quartzJob.getPauseAfterFailure()){ + quartzJob.setIsPause(false); + //更新状态 + quartzJobService.updateIsPause(quartzJob); + } + if(quartzJob.getEmail() != null){ + EmailService emailService = SpringContextHolder.getBean(EmailService.class); + // 邮箱报警 + if(StringUtils.isNoneBlank(quartzJob.getEmail())){ + EmailVo emailVo = taskAlarm(quartzJob, ThrowableUtil.getStackTrace(e)); + emailService.send(emailVo, emailService.find()); + } + } + } finally { + quartzLogRepository.save(log); + } + } + + private EmailVo taskAlarm(QuartzJob quartzJob, String msg) { + EmailVo emailVo = new EmailVo(); + emailVo.setSubject("定时任务【"+ quartzJob.getJobName() +"】执行失败,请尽快处理!"); + Map data = new HashMap<>(16); + data.put("task", quartzJob); + data.put("msg", msg); + TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH)); + Template template = engine.getTemplate("email/taskAlarm.ftl"); + emailVo.setContent(template.render(data)); + List emails = Arrays.asList(quartzJob.getEmail().split("[,,]")); + emailVo.setTos(emails); + return emailVo; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/utils/QuartzManage.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/utils/QuartzManage.java new file mode 100644 index 0000000..e0cf1e0 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/utils/QuartzManage.java @@ -0,0 +1,174 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.utils; + +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.quartz.domain.QuartzJob; +import org.quartz.*; +import org.quartz.impl.triggers.CronTriggerImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import javax.annotation.Resource; +import java.util.Date; +import static org.quartz.TriggerBuilder.newTrigger; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +@Slf4j +@Component +public class QuartzManage { + + private static final String JOB_NAME = "TASK_"; + + @Resource + private Scheduler scheduler; + + public void addJob(QuartzJob quartzJob){ + try { + // 构建job信息 + JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class). + withIdentity(JOB_NAME + quartzJob.getId()).build(); + + //通过触发器名和cron 表达式创建 Trigger + Trigger cronTrigger = newTrigger() + .withIdentity(JOB_NAME + quartzJob.getId()) + .startNow() + .withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression())) + .build(); + + cronTrigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob); + + //重置启动时间 + ((CronTriggerImpl)cronTrigger).setStartTime(new Date()); + + //执行定时任务 + scheduler.scheduleJob(jobDetail,cronTrigger); + + // 暂停任务 + if (quartzJob.getIsPause()) { + pauseJob(quartzJob); + } + } catch (Exception e){ + log.error("创建定时任务失败", e); + throw new BadRequestException("创建定时任务失败"); + } + } + + /** + * 更新job cron表达式 + * @param quartzJob / + */ + public void updateJobCron(QuartzJob quartzJob){ + try { + TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId()); + CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); + // 如果不存在则创建一个定时任务 + if(trigger == null){ + addJob(quartzJob); + trigger = (CronTrigger) scheduler.getTrigger(triggerKey); + } + CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression()); + trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); + //重置启动时间 + ((CronTriggerImpl)trigger).setStartTime(new Date()); + trigger.getJobDataMap().put(QuartzJob.JOB_KEY,quartzJob); + + scheduler.rescheduleJob(triggerKey, trigger); + // 暂停任务 + if (quartzJob.getIsPause()) { + pauseJob(quartzJob); + } + } catch (Exception e){ + log.error("更新定时任务失败", e); + throw new BadRequestException("更新定时任务失败"); + } + + } + + /** + * 删除一个job + * @param quartzJob / + */ + public void deleteJob(QuartzJob quartzJob){ + try { + JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId()); + scheduler.pauseJob(jobKey); + scheduler.deleteJob(jobKey); + } catch (Exception e){ + log.error("删除定时任务失败", e); + throw new BadRequestException("删除定时任务失败"); + } + } + + /** + * 恢复一个job + * @param quartzJob / + */ + public void resumeJob(QuartzJob quartzJob){ + try { + TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId()); + CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); + // 如果不存在则创建一个定时任务 + if(trigger == null) { + addJob(quartzJob); + } + JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId()); + scheduler.resumeJob(jobKey); + } catch (Exception e){ + log.error("恢复定时任务失败", e); + throw new BadRequestException("恢复定时任务失败"); + } + } + + /** + * 立即执行job + * @param quartzJob / + */ + public void runJobNow(QuartzJob quartzJob){ + try { + TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId()); + CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); + // 如果不存在则创建一个定时任务 + if(trigger == null) { + addJob(quartzJob); + } + JobDataMap dataMap = new JobDataMap(); + dataMap.put(QuartzJob.JOB_KEY, quartzJob); + JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId()); + scheduler.triggerJob(jobKey,dataMap); + } catch (Exception e){ + log.error("定时任务执行失败", e); + throw new BadRequestException("定时任务执行失败"); + } + } + + /** + * 暂停一个job + * @param quartzJob / + */ + public void pauseJob(QuartzJob quartzJob){ + try { + JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId()); + scheduler.pauseJob(jobKey); + } catch (Exception e){ + log.error("定时任务暂停失败", e); + throw new BadRequestException("定时任务暂停失败"); + } + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/utils/QuartzRunnable.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/utils/QuartzRunnable.java new file mode 100644 index 0000000..faf334c --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/utils/QuartzRunnable.java @@ -0,0 +1,58 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.quartz.utils; + +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.utils.SpringContextHolder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.ReflectionUtils; +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +/** + * 执行定时任务 + * @author / + */ +@Slf4j +public class QuartzRunnable implements Callable { + + private final Object target; + private final Method method; + private final String params; + + QuartzRunnable(String beanName, String methodName, String params) + throws NoSuchMethodException, SecurityException { + this.target = SpringContextHolder.getBean(beanName); + this.params = params; + + if (StringUtils.isNotBlank(params)) { + this.method = target.getClass().getDeclaredMethod(methodName, String.class); + } else { + this.method = target.getClass().getDeclaredMethod(methodName); + } + } + + @Override + public Object call() throws Exception { + ReflectionUtils.makeAccessible(method); + if (StringUtils.isNotBlank(params)) { + method.invoke(target, params); + } else { + method.invoke(target); + } + return null; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/quartz/utils/YdApiUtil.java b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/utils/YdApiUtil.java new file mode 100644 index 0000000..228ca67 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/quartz/utils/YdApiUtil.java @@ -0,0 +1,31 @@ +package me.zhengjie.modules.quartz.utils; + +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.config.BeanFactory; +import me.zhengjie.constant.Constants; +import me.zhengjie.entity.CtApply; +import me.zhengjie.entity.CtRebot; +import me.zhengjie.entity.quartz.RebotStatu; +import me.zhengjie.entity.quartz.RebotStatuReturn; +import me.zhengjie.entity.quartz.SecreInfo; +import me.zhengjie.enums.RobotStatusEnum; +import me.zhengjie.enums.YesOrNoEnum; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.service.CtRebotService; +import me.zhengjie.utils.HttpClientUtil; + +import java.util.HashMap; +import java.util.Map; + +/** + * 调用影刀发起Api请求工具类 + * + * @author rch + * @create 2022-08-01 + */ +@Slf4j +public class YdApiUtil { + + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/config/ConfigBeanConfiguration.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/config/ConfigBeanConfiguration.java new file mode 100644 index 0000000..8cbc88d --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/config/ConfigBeanConfiguration.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.config; + +import me.zhengjie.modules.security.config.bean.LoginProperties; +import me.zhengjie.modules.security.config.bean.SecurityProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @apiNote 配置文件转换Pojo类的 统一配置 类 + * @author: liaojinlong + * @date: 2020/6/10 19:04 + */ +@Configuration +public class ConfigBeanConfiguration { + + @Bean + @ConfigurationProperties(prefix = "login") + public LoginProperties loginProperties() { + return new LoginProperties(); + } + + @Bean + @ConfigurationProperties(prefix = "jwt") + public SecurityProperties securityProperties() { + return new SecurityProperties(); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/config/SecurityConfig.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/config/SecurityConfig.java new file mode 100644 index 0000000..9067f1c --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/config/SecurityConfig.java @@ -0,0 +1,207 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.config; + +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.config.PropertiesConfig; +import me.zhengjie.modules.security.config.bean.SecurityProperties; +import me.zhengjie.modules.security.security.JwtAccessDeniedHandler; +import me.zhengjie.modules.security.security.JwtAuthenticationEntryPoint; +import me.zhengjie.modules.security.security.TokenConfigurer; +import me.zhengjie.modules.security.security.TokenProvider; +import me.zhengjie.modules.security.service.OnlineUserService; +import me.zhengjie.modules.security.service.UserCacheClean; +import me.zhengjie.service.LoginIpService; +import me.zhengjie.utils.enums.RequestMethodEnum; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.core.GrantedAuthorityDefaults; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.filter.CorsFilter; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; + +import javax.annotation.Resource; +import java.util.*; + +/** + * @author Zheng Jie + */ +@Configuration +@EnableWebSecurity +@RequiredArgsConstructor +@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + private final TokenProvider tokenProvider; + private final CorsFilter corsFilter; + private final JwtAuthenticationEntryPoint authenticationErrorHandler; + private final JwtAccessDeniedHandler jwtAccessDeniedHandler; + private final ApplicationContext applicationContext; + private final SecurityProperties properties; + private final OnlineUserService onlineUserService; + private final UserCacheClean userCacheClean; + private final LoginIpService loginIpService; + @Resource + private PropertiesConfig propertiesConfig; + + @Bean + GrantedAuthorityDefaults grantedAuthorityDefaults() { + // 去除 ROLE_ 前缀 + return new GrantedAuthorityDefaults(""); + } + + @Bean + public PasswordEncoder passwordEncoder() { + // 密码加密方式 + return new BCryptPasswordEncoder(); + } + + @Override + protected void configure(HttpSecurity httpSecurity) throws Exception { + // 搜寻匿名标记 url: @AnonymousAccess + // Map handlerMethodMap = applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods(); + RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) applicationContext.getBean("requestMappingHandlerMapping"); + Map handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods(); + + // 获取匿名标记 + Map> anonymousUrls = getAnonymousUrl(handlerMethodMap); + httpSecurity + // 禁用 CSRF + .csrf().disable() + .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class) + // 授权异常 + .exceptionHandling() + .authenticationEntryPoint(authenticationErrorHandler) + .accessDeniedHandler(jwtAccessDeniedHandler) + // 防止iframe 造成跨域 + .and() + .headers() + .frameOptions() + .disable() + // 不创建会话 + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + // 静态资源等等 + .antMatchers( + HttpMethod.GET, + "/*.html", + "/**/*.html", + "/**/*.css", + "/**/*.js", + "/webSocket/**" + ).permitAll() + // swagger 文档 + .antMatchers("/swagger-ui.html").permitAll() + .antMatchers("/doc.html").permitAll() + .antMatchers("/swagger-resources/**").permitAll() + .antMatchers("/webjars/**").permitAll() + .antMatchers("/*/api-docs").permitAll() + // 文件 + .antMatchers("/avatar/**").permitAll() + .antMatchers("/file/**").permitAll() + // 图片上传 + .antMatchers("/api/file/**").permitAll() + // 静态资源访问 + .antMatchers(propertiesConfig.getUploadPrefix()+"/**").permitAll() + // 阿里巴巴 druid + .antMatchers("/druid/**").permitAll() + // 放行OPTIONS请求 + .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() + // 代理后台 + .antMatchers("/proxyAdmin/**").permitAll() + // 自定义匿名访问所有url放行:允许匿名和带Token访问,细腻化到每个 Request 类型 + // GET + .antMatchers(HttpMethod.GET, anonymousUrls.get(RequestMethodEnum.GET.getType()).toArray(new String[0])).permitAll() + // POST + .antMatchers(HttpMethod.POST, anonymousUrls.get(RequestMethodEnum.POST.getType()).toArray(new String[0])).permitAll() + // PUT + .antMatchers(HttpMethod.PUT, anonymousUrls.get(RequestMethodEnum.PUT.getType()).toArray(new String[0])).permitAll() + // PATCH + .antMatchers(HttpMethod.PATCH, anonymousUrls.get(RequestMethodEnum.PATCH.getType()).toArray(new String[0])).permitAll() + // DELETE + .antMatchers(HttpMethod.DELETE, anonymousUrls.get(RequestMethodEnum.DELETE.getType()).toArray(new String[0])).permitAll() + // 所有类型的接口都放行 + .antMatchers(anonymousUrls.get(RequestMethodEnum.ALL.getType()).toArray(new String[0])).permitAll() + // 所有请求都需要认证 + .anyRequest().authenticated() + .and().apply(securityConfigurerAdapter()); + } + + private Map> getAnonymousUrl(Map handlerMethodMap) { + Map> anonymousUrls = new HashMap<>(6); + Set get = new HashSet<>(); + Set post = new HashSet<>(); + Set put = new HashSet<>(); + Set patch = new HashSet<>(); + Set delete = new HashSet<>(); + Set all = new HashSet<>(); + for (Map.Entry infoEntry : handlerMethodMap.entrySet()) { + HandlerMethod handlerMethod = infoEntry.getValue(); + AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class); + if (null != anonymousAccess) { + List requestMethods = new ArrayList<>(infoEntry.getKey().getMethodsCondition().getMethods()); + RequestMethodEnum request = RequestMethodEnum.find(requestMethods.size() == 0 ? RequestMethodEnum.ALL.getType() : requestMethods.get(0).name()); + switch (Objects.requireNonNull(request)) { + case GET: + get.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + case POST: + post.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + case PUT: + put.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + case PATCH: + patch.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + case DELETE: + delete.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + default: + all.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + } + } + } + anonymousUrls.put(RequestMethodEnum.GET.getType(), get); + anonymousUrls.put(RequestMethodEnum.POST.getType(), post); + anonymousUrls.put(RequestMethodEnum.PUT.getType(), put); + anonymousUrls.put(RequestMethodEnum.PATCH.getType(), patch); + anonymousUrls.put(RequestMethodEnum.DELETE.getType(), delete); + anonymousUrls.put(RequestMethodEnum.ALL.getType(), all); + return anonymousUrls; + } + + private TokenConfigurer securityConfigurerAdapter() { + return new TokenConfigurer(tokenProvider, properties, onlineUserService, userCacheClean,loginIpService); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/config/bean/LoginCode.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/config/bean/LoginCode.java new file mode 100644 index 0000000..fefd252 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/config/bean/LoginCode.java @@ -0,0 +1,61 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.config.bean; + +import lombok.Data; + +/** + * 登录验证码配置信息 + * + * @author liaojinlong + * @date 2020/6/10 18:53 + */ +@Data +public class LoginCode { + + /** + * 验证码配置 + */ + private LoginCodeEnum codeType; + /** + * 验证码有效期 分钟 + */ + private Long expiration = 2L; + /** + * 验证码内容长度 + */ + private int length = 2; + /** + * 验证码宽度 + */ + private int width = 111; + /** + * 验证码高度 + */ + private int height = 36; + /** + * 验证码字体 + */ + private String fontName; + /** + * 字体大小 + */ + private int fontSize = 25; + + public LoginCodeEnum getCodeType() { + return codeType; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/config/bean/LoginCodeEnum.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/config/bean/LoginCodeEnum.java new file mode 100644 index 0000000..9ff398f --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/config/bean/LoginCodeEnum.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.config.bean; + +/** + * 验证码配置枚举 + * + * @author: liaojinlong + * @date: 2020/6/10 17:40 + */ + +public enum LoginCodeEnum { + /** + * 算数 + */ + arithmetic, + /** + * 中文 + */ + chinese, + /** + * 中文闪图 + */ + chinese_gif, + /** + * 闪图 + */ + gif, + spec +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/config/bean/LoginProperties.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/config/bean/LoginProperties.java new file mode 100644 index 0000000..b13f173 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/config/bean/LoginProperties.java @@ -0,0 +1,135 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version loginCode.length.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-loginCode.length.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.config.bean; + +import com.wf.captcha.*; +import com.wf.captcha.base.Captcha; +import lombok.Data; +import me.zhengjie.exception.BadConfigurationException; +import me.zhengjie.utils.StringUtils; + +import java.awt.*; +import java.util.Objects; + +/** + * 配置文件读取 + * + * @author liaojinlong + * @date loginCode.length0loginCode.length0/6/10 17:loginCode.length6 + */ +@Data +public class LoginProperties { + + /** + * 账号单用户 登录 + */ + private boolean singleLogin = false; + + private LoginCode loginCode; + + /** + * 用户登录信息缓存 + */ + private boolean cacheEnable; + + public boolean isSingleLogin() { + return singleLogin; + } + + public boolean isCacheEnable() { + return cacheEnable; + } + + /** + * 获取验证码生产类 + * + * @return / + */ + public Captcha getCaptcha() { + if (Objects.isNull(loginCode)) { + loginCode = new LoginCode(); + if (Objects.isNull(loginCode.getCodeType())) { + loginCode.setCodeType(LoginCodeEnum.arithmetic); + } + } + return switchCaptcha(loginCode); + } + + /** + * 依据配置信息生产验证码 + * + * @param loginCode 验证码配置信息 + * @return / + */ + private Captcha switchCaptcha(LoginCode loginCode) { + Captcha captcha; + synchronized (this) { + switch (loginCode.getCodeType()) { + case arithmetic: + // 算术类型 https://gitee.com/whvse/EasyCaptcha + captcha = new FixedArithmeticCaptcha(loginCode.getWidth(), loginCode.getHeight()); + // 几位数运算,默认是两位 + captcha.setLen(loginCode.getLength()); + break; + case chinese: + captcha = new ChineseCaptcha(loginCode.getWidth(), loginCode.getHeight()); + captcha.setLen(loginCode.getLength()); + break; + case chinese_gif: + captcha = new ChineseGifCaptcha(loginCode.getWidth(), loginCode.getHeight()); + captcha.setLen(loginCode.getLength()); + break; + case gif: + captcha = new GifCaptcha(loginCode.getWidth(), loginCode.getHeight()); + captcha.setLen(loginCode.getLength()); + break; + case spec: + captcha = new SpecCaptcha(loginCode.getWidth(), loginCode.getHeight()); + captcha.setLen(loginCode.getLength()); + break; + default: + throw new BadConfigurationException("验证码配置信息错误!正确配置查看 LoginCodeEnum "); + } + } + if(StringUtils.isNotBlank(loginCode.getFontName())){ + captcha.setFont(new Font(loginCode.getFontName(), Font.PLAIN, loginCode.getFontSize())); + } + return captcha; + } + + static class FixedArithmeticCaptcha extends ArithmeticCaptcha { + public FixedArithmeticCaptcha(int width, int height) { + super(width, height); + } + + @Override + protected char[] alphas() { + // 生成随机数字和运算符 + int n1 = num(1, 10), n2 = num(1, 10); + int opt = num(3); + + // 计算结果 + int res = new int[]{n1 + n2, n1 - n2, n1 * n2}[opt]; + // 转换为字符运算符 + char optChar = "+-x".charAt(opt); + + this.setArithmeticString(String.format("%s%c%s=?", n1, optChar, n2)); + this.chars = String.valueOf(res); + + return chars.toCharArray(); + } + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/config/bean/SecurityProperties.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/config/bean/SecurityProperties.java new file mode 100644 index 0000000..16ec3cf --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/config/bean/SecurityProperties.java @@ -0,0 +1,72 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.config.bean; + +import lombok.Data; + +/** + * Jwt参数配置 + * + * @author Zheng Jie + * @date 2019年11月28日 + */ +@Data +public class SecurityProperties { + + /** + * Request Headers : Authorization + */ + private String header; + + /** + * 令牌前缀,最后留个空格 Bearer + */ + private String tokenStartWith; + + /** + * 必须使用最少88位的Base64对该令牌进行编码 + */ + private String base64Secret; + + /** + * 令牌过期时间 此处单位/毫秒 + */ + private Long tokenValidityInSeconds; + + /** + * 在线用户 key,根据 key 查询 redis 中在线用户的数据 + */ + private String onlineKey; + + /** + * 验证码 key + */ + private String codeKey; + + /** + * token 续期检查 + */ + private Long detect; + + /** + * 续期时间 + */ + private Long renew; + + public String getTokenStartWith() { + return tokenStartWith + " "; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/rest/AuthorizationController.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/rest/AuthorizationController.java new file mode 100644 index 0000000..c9180cf --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/rest/AuthorizationController.java @@ -0,0 +1,201 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.rest; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import com.wf.captcha.base.Captcha; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.annotation.Log; +import me.zhengjie.annotation.rest.AnonymousDeleteMapping; +import me.zhengjie.annotation.rest.AnonymousGetMapping; +import me.zhengjie.annotation.rest.AnonymousPostMapping; +import me.zhengjie.annotation.type.LogActionType; +import me.zhengjie.config.RsaProperties; +import me.zhengjie.dto.Dto; +import me.zhengjie.error.ErrorCodeEnum; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.security.config.bean.LoginCodeEnum; +import me.zhengjie.modules.security.config.bean.LoginProperties; +import me.zhengjie.modules.security.config.bean.SecurityProperties; +import me.zhengjie.modules.security.security.TokenProvider; +import me.zhengjie.modules.security.service.OnlineUserService; +import me.zhengjie.modules.security.service.dto.AuthUserDto; +import me.zhengjie.modules.security.service.dto.JwtUserDto; +import me.zhengjie.modules.utils.GoogleAuthenticatorUtil; +import me.zhengjie.service.LoginIpService; +import me.zhengjie.service.SettingSiteService; +import me.zhengjie.utils.*; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import static me.zhengjie.error.ErrorCodeEnum.LOGIN_PWD_ERROR; + +/** + * @author Zheng Jie + * @date 2018-11-23 + * 授权、根据token获取用户详细信息 + */ +@Slf4j +@RestController +@RequestMapping("/api/auth") +@RequiredArgsConstructor +@Api(tags = "系统:系统授权接口") +public class AuthorizationController { + private final SecurityProperties properties; + private final RedisUtils redisUtils; + private final OnlineUserService onlineUserService; + private final TokenProvider tokenProvider; + private final AuthenticationManagerBuilder authenticationManagerBuilder; + private final LoginIpService loginIpService; + + @Resource + private LoginProperties loginProperties; + @Resource + private SettingSiteService settingSiteService; + + @Log(value = "用户登录", type = LogActionType.LOGIN) + @ApiOperation("登录授权") + @AnonymousPostMapping(value = "/login") + public Object login(@Validated @RequestBody AuthUserDto authUser, HttpServletRequest request) throws Exception { + String ip = StringUtils.getIp(request); + if (!loginIpService.whiteListFlag(ip)) { + return Dto.getInstance(ErrorCodeEnum.BLOCKED_LOGIN_IP_ERROR); + } + + String BLOCKED_ACCOUNT = String.format(RedisUtils.BLOCKED_ACCOUNT, authUser.getUsername()); + Object obj = redisUtils.get(BLOCKED_ACCOUNT); + if (ObjectUtil.isNotEmpty(obj)) { + return Dto.getInstance(ErrorCodeEnum.BLOCKED_ACCOUNT_ERROR); + } + + // 如果Google Auth开启使用google Auth 验证 + if (settingSiteService.getGooleAuthSwitch()) { + // 第二个参数是 host -TODO 待确认 request.getRemoteHost() 是否是符合要求的域 + if (!GoogleAuthenticatorUtil.authcode(authUser.getCode(), GoogleAuthenticatorUtil.genSecret(authUser.getUsername(), request.getRemoteHost()))) { +// throw new BadRequestException("验证码错误"); + return Dto.getInstance(ErrorCodeEnum.ERROR_2222); + } + } else { + // 查询验证码 + String code = (String) redisUtils.get(authUser.getUuid()); + // 清除验证码 + redisUtils.del(authUser.getUuid()); + if (StringUtils.isBlank(code)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_2223); + } + if (StringUtils.isBlank(authUser.getCode()) || !authUser.getCode().equalsIgnoreCase(code)) { + return Dto.getInstance(ErrorCodeEnum.ERROR_2222); + } + } + + // 密码解密 + Authentication authentication = null; + try { + + String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, authUser.getPassword()); + + UsernamePasswordAuthenticationToken authenticationToken = + new UsernamePasswordAuthenticationToken(authUser.getUsername(), password); + authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); + SecurityContextHolder.getContext().setAuthentication(authentication); + } catch (Exception e) { + String key = String.format(RedisUtils.LOGIN_FAIL_COUNT, authUser.getUsername()); + Long count = redisUtils.incrAndExpire(key, 300); + if (count >=3) { + // 冻结账户,24小时内不允许登录 + Map map = MapUtil.of("time", DateUtil.getCurrentTime()); + redisUtils.set(BLOCKED_ACCOUNT, map, 3600 * 24); + redisUtils.del(key); + } + + return Dto.getInstance(LOGIN_PWD_ERROR); + } + + + // 生成令牌与第三方系统获取令牌方式 + // UserDetails userDetails = userDetailsService.loadUserByUsername(userInfo.getUsername()); + // Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + // SecurityContextHolder.getContext().setAuthentication(authentication); + String token = tokenProvider.createToken(authentication); + final JwtUserDto jwtUserDto = (JwtUserDto) authentication.getPrincipal(); + // 保存在线信息 + onlineUserService.save(jwtUserDto, token, request); + // 返回 token 与 用户信息 + Map authInfo = new HashMap(2) {{ + put("token", properties.getTokenStartWith() + token); + put("user", jwtUserDto); + }}; + if (loginProperties.isSingleLogin()) { + //踢掉之前已经登录的token + onlineUserService.checkLoginOnUser(authUser.getUsername(), token); + } + return ResponseEntity.ok(authInfo); + } + + @ApiOperation("获取用户信息") + @GetMapping(value = "/info") + public ResponseEntity getUserInfo() { + return ResponseEntity.ok(SecurityUtils.getCurrentUser()); + } + + @ApiOperation("获取验证码") + @AnonymousGetMapping(value = "/code") + public ResponseEntity getCode() { + // 获取运算的结果 + Captcha captcha = loginProperties.getCaptcha(); + String uuid = properties.getCodeKey() + IdUtil.simpleUUID(); + //当验证码类型为 arithmetic时且长度 >= 2 时,captcha.text()的结果有几率为浮点型 + String captchaValue = captcha.text(); + if (captcha.getCharType() - 1 == LoginCodeEnum.arithmetic.ordinal() && captchaValue.contains(".")) { + captchaValue = captchaValue.split("\\.")[0]; + } + // 保存 + redisUtils.set(uuid, captchaValue, loginProperties.getLoginCode().getExpiration(), TimeUnit.MINUTES); + // 验证码信息 + Map imgResult = new HashMap(2) {{ + put("img", captcha.toBase64()); + put("uuid", uuid); + }}; + return ResponseEntity.ok(imgResult); + } + + @ApiOperation("退出登录") + @AnonymousDeleteMapping(value = "/logout") + public ResponseEntity logout(HttpServletRequest request) { + onlineUserService.logout(tokenProvider.getToken(request)); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/rest/OnlineController.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/rest/OnlineController.java new file mode 100644 index 0000000..016f06f --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/rest/OnlineController.java @@ -0,0 +1,68 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.modules.security.service.OnlineUserService; +import me.zhengjie.utils.EncryptUtils; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Set; + +/** + * @author Zheng Jie + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/online") +@Api(tags = "系统:在线用户管理") +public class OnlineController { + + private final OnlineUserService onlineUserService; + + @ApiOperation("查询在线用户") + @GetMapping + @PreAuthorize("@el.check()") + public ResponseEntity query(String filter, Pageable pageable){ + return new ResponseEntity<>(onlineUserService.getAll(filter, pageable),HttpStatus.OK); + } + + @ApiOperation("导出数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check()") + public void download(HttpServletResponse response, String filter) throws IOException { + onlineUserService.download(onlineUserService.getAll(filter), response); + } + + @ApiOperation("踢出用户") + @DeleteMapping + @PreAuthorize("@el.check()") + public ResponseEntity delete(@RequestBody Set keys) throws Exception { + for (String key : keys) { + // 解密Key + key = EncryptUtils.desDecrypt(key); + onlineUserService.kickOut(key); + } + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/security/JwtAccessDeniedHandler.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/security/JwtAccessDeniedHandler.java new file mode 100644 index 0000000..8b3f8c1 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/security/JwtAccessDeniedHandler.java @@ -0,0 +1,37 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.security; + +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author Zheng Jie + */ +@Component +public class JwtAccessDeniedHandler implements AccessDeniedHandler { + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException { + //当用户在没有授权的情况下访问受保护的REST资源时,将调用此方法发送403 Forbidden响应 + response.sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage()); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/security/JwtAuthenticationEntryPoint.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/security/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..f881586 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/security/JwtAuthenticationEntryPoint.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.security; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author Zheng Jie + */ +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, + HttpServletResponse response, + AuthenticationException authException) throws IOException { + // 当用户尝试访问安全的REST资源而不提供任何凭据时,将调用此方法发送401 响应 + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException==null?"Unauthorized":authException.getMessage()); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/security/TokenConfigurer.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/security/TokenConfigurer.java new file mode 100644 index 0000000..9e4e533 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/security/TokenConfigurer.java @@ -0,0 +1,45 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.security; + +import lombok.RequiredArgsConstructor; +import me.zhengjie.modules.security.config.bean.SecurityProperties; +import me.zhengjie.modules.security.service.OnlineUserService; +import me.zhengjie.modules.security.service.UserCacheClean; +import me.zhengjie.service.LoginIpService; +import org.springframework.security.config.annotation.SecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +/** + * @author / + */ +@RequiredArgsConstructor +public class TokenConfigurer extends SecurityConfigurerAdapter { + + private final TokenProvider tokenProvider; + private final SecurityProperties properties; + private final OnlineUserService onlineUserService; + private final UserCacheClean userCacheClean; + private final LoginIpService loginIpService; + + @Override + public void configure(HttpSecurity http) { + TokenFilter customFilter = new TokenFilter(tokenProvider, properties, onlineUserService, userCacheClean,loginIpService); + http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/security/TokenFilter.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/security/TokenFilter.java new file mode 100644 index 0000000..db96094 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/security/TokenFilter.java @@ -0,0 +1,111 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.security; + +import cn.hutool.core.util.StrUtil; +import io.jsonwebtoken.ExpiredJwtException; +import lombok.RequiredArgsConstructor; +import me.zhengjie.modules.security.config.bean.SecurityProperties; +import me.zhengjie.modules.security.service.OnlineUserService; +import me.zhengjie.modules.security.service.UserCacheClean; +import me.zhengjie.modules.security.service.dto.OnlineUserDto; +import me.zhengjie.service.LoginIpService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.GenericFilterBean; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.Objects; + +/** + * @author / + */ +@RequiredArgsConstructor +public class TokenFilter extends GenericFilterBean { + private static final Logger log = LoggerFactory.getLogger(TokenFilter.class); + + + private final TokenProvider tokenProvider; + private final SecurityProperties properties; + private final OnlineUserService onlineUserService; + private final UserCacheClean userCacheClean; + private final LoginIpService loginIpService; + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; + // 验证 +// String ip = me.zhengjie.utils.StringUtils.getIp(httpServletRequest); +// if (!loginIpService.whiteListFlag(ip)) { +// Dto dto = Dto.getInstance(ErrorCodeEnum.BLOCKED_LOGIN_IP_ERROR); +//// throw new BadRequestException(ErrorCodeEnum.BLOCKED_LOGIN_IP_ERROR); +// servletResponse.setContentType("application/json;charset=UTF-8"); +// servletResponse.getWriter().write(JSONUtil.toJsonStr(dto)); +// +// return; +// } + + String token = resolveToken(httpServletRequest); + // 对于 Token 为空的不需要去查 Redis + if (StrUtil.isNotBlank(token)) { + OnlineUserDto onlineUserDto = null; + boolean cleanUserCache = false; + try { + onlineUserDto = onlineUserService.getOne(properties.getOnlineKey() + token); + } catch (ExpiredJwtException e) { + log.error(e.getMessage()); + cleanUserCache = true; + } finally { + if (cleanUserCache || Objects.isNull(onlineUserDto)) { + userCacheClean.cleanUserCache(String.valueOf(tokenProvider.getClaims(token).get(TokenProvider.AUTHORITIES_KEY))); + } + } + if (onlineUserDto != null && StringUtils.hasText(token)) { + Authentication authentication = tokenProvider.getAuthentication(token); + SecurityContextHolder.getContext().setAuthentication(authentication); + // Token 续期 +// tokenProvider.checkRenewal(token); + } + } + filterChain.doFilter(servletRequest, servletResponse); + } + + /** + * 初步检测Token + * + * @param request / + * @return / + */ + private String resolveToken(HttpServletRequest request) { + String bearerToken = request.getHeader(properties.getHeader()); + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(properties.getTokenStartWith())) { + // 去掉令牌前缀 + return bearerToken.replace(properties.getTokenStartWith(), ""); + } else { + log.debug("非法Token:{}", bearerToken); + } + return null; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/security/TokenProvider.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/security/TokenProvider.java new file mode 100644 index 0000000..db98fba --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/security/TokenProvider.java @@ -0,0 +1,123 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.security; + +import cn.hutool.core.date.DateField; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import io.jsonwebtoken.*; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.modules.security.config.bean.SecurityProperties; +import me.zhengjie.utils.RedisUtils; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.User; +import org.springframework.stereotype.Component; +import javax.servlet.http.HttpServletRequest; +import java.security.Key; +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * @author / + */ +@Slf4j +@Component +public class TokenProvider implements InitializingBean { + + private final SecurityProperties properties; + private final RedisUtils redisUtils; + public static final String AUTHORITIES_KEY = "user"; + private JwtParser jwtParser; + private JwtBuilder jwtBuilder; + + public TokenProvider(SecurityProperties properties, RedisUtils redisUtils) { + this.properties = properties; + this.redisUtils = redisUtils; + } + + @Override + public void afterPropertiesSet() { + byte[] keyBytes = Decoders.BASE64.decode(properties.getBase64Secret()); + Key key = Keys.hmacShaKeyFor(keyBytes); + jwtParser = Jwts.parserBuilder() + .setSigningKey(key) + .build(); + jwtBuilder = Jwts.builder() + .signWith(key, SignatureAlgorithm.HS512); + } + + /** + * 创建Token 设置永不过期, + * Token 的时间有效性转到Redis 维护 + * + * @param authentication / + * @return / + */ + public String createToken(Authentication authentication) { + return jwtBuilder + // 加入ID确保生成的 Token 都不一致 + .setId(IdUtil.simpleUUID()) + .claim(AUTHORITIES_KEY, authentication.getName()) + .setSubject(authentication.getName()) + .compact(); + } + + /** + * 依据Token 获取鉴权信息 + * + * @param token / + * @return / + */ + Authentication getAuthentication(String token) { + Claims claims = getClaims(token); + User principal = new User(claims.getSubject(), "******", new ArrayList<>()); + return new UsernamePasswordAuthenticationToken(principal, token, new ArrayList<>()); + } + + public Claims getClaims(String token) { + return jwtParser + .parseClaimsJws(token) + .getBody(); + } + + /** + * @param token 需要检查的token + */ + public void checkRenewal(String token) { + // 判断是否续期token,计算token的过期时间 + long time = redisUtils.getExpire(properties.getOnlineKey() + token) * 1000; + Date expireDate = DateUtil.offset(new Date(), DateField.MILLISECOND, (int) time); + // 判断当前时间与过期时间的时间差 + long differ = expireDate.getTime() - System.currentTimeMillis(); + // 如果在续期检查的范围内,则续期 + if (differ <= properties.getDetect()) { + long renew = time + properties.getRenew(); + redisUtils.expire(properties.getOnlineKey() + token, renew, TimeUnit.MILLISECONDS); + } + } + + public String getToken(HttpServletRequest request) { + final String requestHeader = request.getHeader(properties.getHeader()); + if (requestHeader != null && requestHeader.startsWith(properties.getTokenStartWith())) { + return requestHeader.substring(7); + } + return null; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/service/OnlineUserService.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/service/OnlineUserService.java new file mode 100644 index 0000000..96ebec4 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/service/OnlineUserService.java @@ -0,0 +1,191 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.service; + +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.modules.security.config.bean.SecurityProperties; +import me.zhengjie.modules.security.service.dto.JwtUserDto; +import me.zhengjie.modules.security.service.dto.OnlineUserDto; +import me.zhengjie.utils.*; +import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** + * @author Zheng Jie + * @date 2019年10月26日21:56:27 + */ +@Service +@Slf4j +public class OnlineUserService { + + private final SecurityProperties properties; + private final RedisUtils redisUtils; + + public OnlineUserService(SecurityProperties properties, RedisUtils redisUtils) { + this.properties = properties; + this.redisUtils = redisUtils; + } + + /** + * 保存在线用户信息 + * @param jwtUserDto / + * @param token / + * @param request / + */ + public void save(JwtUserDto jwtUserDto, String token, HttpServletRequest request){ + String dept = /*jwtUserDto.getUser().getDept().getName();*/null; + String ip = StringUtils.getIp(request); + String browser = StringUtils.getBrowser(request); +// String address = StringUtils.getCityInfo(ip); + OnlineUserDto onlineUserDto = null; + try { + onlineUserDto = new OnlineUserDto(jwtUserDto.getUsername(), jwtUserDto.getUser().getNickName(), dept, browser , ip, null, EncryptUtils.desEncrypt(token), new Date()); + } catch (Exception e) { + log.error(e.getMessage(),e); + } + redisUtils.set(properties.getOnlineKey() + token, onlineUserDto, properties.getTokenValidityInSeconds()/1000); + } + + /** + * 查询全部数据 + * @param filter / + * @param pageable / + * @return / + */ + public Map getAll(String filter, Pageable pageable){ + List onlineUserDtos = getAll(filter); + return PageUtil.toPage( + PageUtil.toPage(pageable.getPageNumber(),pageable.getPageSize(), onlineUserDtos), + onlineUserDtos.size() + ); + } + + /** + * 查询全部数据,不分页 + * @param filter / + * @return / + */ + public List getAll(String filter){ + List keys = redisUtils.scan(properties.getOnlineKey() + "*"); + Collections.reverse(keys); + List onlineUserDtos = new ArrayList<>(); + for (String key : keys) { + OnlineUserDto onlineUserDto = (OnlineUserDto) redisUtils.get(key); + if(StringUtils.isNotBlank(filter)){ + if(onlineUserDto.toString().contains(filter)){ + onlineUserDtos.add(onlineUserDto); + } + } else { + onlineUserDtos.add(onlineUserDto); + } + } + onlineUserDtos.sort((o1, o2) -> o2.getLoginTime().compareTo(o1.getLoginTime())); + return onlineUserDtos; + } + + /** + * 踢出用户 + * @param key / + */ + public void kickOut(String key){ + key = properties.getOnlineKey() + key; + redisUtils.del(key); + } + + /** + * 退出登录 + * @param token / + */ + public void logout(String token) { + String key = properties.getOnlineKey() + token; + redisUtils.del(key); + } + + /** + * 导出 + * @param all / + * @param response / + * @throws IOException / + */ + public void download(List all, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (OnlineUserDto user : all) { + Map map = new LinkedHashMap<>(); + map.put("用户名", user.getUserName()); + map.put("部门", user.getDept()); + map.put("登录IP", user.getIp()); + map.put("登录地点", user.getAddress()); + map.put("浏览器", user.getBrowser()); + map.put("登录日期", user.getLoginTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + /** + * 查询用户 + * @param key / + * @return / + */ + public OnlineUserDto getOne(String key) { + return (OnlineUserDto)redisUtils.get(key); + } + + /** + * 检测用户是否在之前已经登录,已经登录踢下线 + * @param userName 用户名 + */ + public void checkLoginOnUser(String userName, String igoreToken){ + List onlineUserDtos = getAll(userName); + if(onlineUserDtos ==null || onlineUserDtos.isEmpty()){ + return; + } + for(OnlineUserDto onlineUserDto : onlineUserDtos){ + if(onlineUserDto.getUserName().equals(userName)){ + try { + String token =EncryptUtils.desDecrypt(onlineUserDto.getKey()); + if(StringUtils.isNotBlank(igoreToken)&&!igoreToken.equals(token)){ + this.kickOut(token); + }else if(StringUtils.isBlank(igoreToken)){ + this.kickOut(token); + } + } catch (Exception e) { + log.error("checkUser is error",e); + } + } + } + } + + /** + * 根据用户名强退用户 + * @param username / + */ + @Async + public void kickOutForUsername(String username) throws Exception { + List onlineUsers = getAll(username); + for (OnlineUserDto onlineUser : onlineUsers) { + if (onlineUser.getUserName().equals(username)) { + String token =EncryptUtils.desDecrypt(onlineUser.getKey()); + kickOut(token); + } + } + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/service/UserCacheClean.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/service/UserCacheClean.java new file mode 100644 index 0000000..3f9fe5b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/service/UserCacheClean.java @@ -0,0 +1,49 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zhengjie.modules.security.service; + +import me.zhengjie.utils.StringUtils; +import org.springframework.stereotype.Component; + +/** + * @author: liaojinlong + * @date: 2020/6/11 18:01 + * @apiNote: 用于清理 用户登录信息缓存,为防止Spring循环依赖与安全考虑 ,单独构成工具类 + */ +@Component +public class UserCacheClean { + + /** + * 清理特定用户缓存信息
+ * 用户信息变更时 + * + * @param userName / + */ + public void cleanUserCache(String userName) { + if (StringUtils.isNotEmpty(userName)) { + UserDetailsServiceImpl.userDtoCache.remove(userName); + } + } + + /** + * 清理所有用户的缓存信息
+ * ,如发生角色授权信息变化,可以简便的全部失效缓存 + */ + public void cleanAll() { + UserDetailsServiceImpl.userDtoCache.clear(); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/service/UserDetailsServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/service/UserDetailsServiceImpl.java new file mode 100644 index 0000000..c3657d1 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/service/UserDetailsServiceImpl.java @@ -0,0 +1,94 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.service; + +import lombok.RequiredArgsConstructor; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.exception.EntityNotFoundException; +import me.zhengjie.modules.security.config.bean.LoginProperties; +import me.zhengjie.modules.security.service.dto.JwtUserDto; +import me.zhengjie.modules.system.service.DataService; +import me.zhengjie.modules.system.service.RoleService; +import me.zhengjie.modules.system.service.UserService; +import me.zhengjie.modules.system.service.dto.UserDto; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author Zheng Jie + * @date 2018-11-22 + */ +@RequiredArgsConstructor +@Service("userDetailsService") +public class UserDetailsServiceImpl implements UserDetailsService { + private final UserService userService; + private final RoleService roleService; + private final DataService dataService; + private final LoginProperties loginProperties; + + public void setEnableCache(boolean enableCache) { + this.loginProperties.setCacheEnable(enableCache); + } + + /** + * 用户信息缓存 + * + * @see {@link UserCacheClean} + */ + static Map userDtoCache = new ConcurrentHashMap<>(); + + @Override + public JwtUserDto loadUserByUsername(String username) { + boolean searchDb = true; + JwtUserDto jwtUserDto = null; + if (loginProperties.isCacheEnable() && userDtoCache.containsKey(username)) { + jwtUserDto = userDtoCache.get(username); + // 检查dataScope是否修改 + List dataScopes = jwtUserDto.getDataScopes(); + dataScopes.clear(); + dataScopes.addAll(dataService.getDeptIds(jwtUserDto.getUser())); + searchDb = false; + } + if (searchDb) { + UserDto user; + try { + user = userService.findByName(username); + } catch (EntityNotFoundException e) { + // SpringSecurity会自动转换UsernameNotFoundException为BadCredentialsException + throw new UsernameNotFoundException("", e); + } + if (user == null) { + throw new UsernameNotFoundException(""); + } else { + if (!user.getEnabled()) { + throw new BadRequestException("账号未激活!"); + } + jwtUserDto = new JwtUserDto( + user, + dataService.getDeptIds(user), + roleService.mapToGrantedAuthorities(user) + ); + userDtoCache.put(username, jwtUserDto); + } + } + return jwtUserDto; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/service/dto/AuthUserDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/service/dto/AuthUserDto.java new file mode 100644 index 0000000..5219fc5 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/service/dto/AuthUserDto.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.service.dto; + +import lombok.Getter; +import lombok.Setter; +import javax.validation.constraints.NotBlank; + +/** + * @author Zheng Jie + * @date 2018-11-30 + */ +@Getter +@Setter +public class AuthUserDto { + + @NotBlank + private String username; + + @NotBlank + private String password; + + private String code; + + private String uuid = ""; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/service/dto/JwtUserDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/service/dto/JwtUserDto.java new file mode 100644 index 0000000..00f4372 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/service/dto/JwtUserDto.java @@ -0,0 +1,82 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.service.dto; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.AllArgsConstructor; +import lombok.Getter; +import me.zhengjie.modules.system.service.dto.UserDto; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Getter +@AllArgsConstructor +public class JwtUserDto implements UserDetails { + + private final UserDto user; + + private final List dataScopes; + + @JSONField(serialize = false) + private final List authorities; + + public Set getRoles() { + return authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet()); + } + + @Override + @JSONField(serialize = false) + public String getPassword() { + return user.getPassword(); + } + + @Override + @JSONField(serialize = false) + public String getUsername() { + return user.getUsername(); + } + + @JSONField(serialize = false) + @Override + public boolean isAccountNonExpired() { + return true; + } + + @JSONField(serialize = false) + @Override + public boolean isAccountNonLocked() { + return true; + } + + @JSONField(serialize = false) + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + @JSONField(serialize = false) + public boolean isEnabled() { + return user.getEnabled(); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/security/service/dto/OnlineUserDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/security/service/dto/OnlineUserDto.java new file mode 100644 index 0000000..290ab6d --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/security/service/dto/OnlineUserDto.java @@ -0,0 +1,73 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.service.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import java.util.Date; + +/** + * 在线用户 + * @author Zheng Jie + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class OnlineUserDto { + + /** + * 用户名 + */ + private String userName; + + /** + * 昵称 + */ + private String nickName; + + /** + * 岗位 + */ + private String dept; + + /** + * 浏览器 + */ + private String browser; + + /** + * IP + */ + private String ip; + + /** + * 地址 + */ + private String address; + + /** + * token + */ + private String key; + + /** + * 登录时间 + */ + private Date loginTime; + + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Dept.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Dept.java new file mode 100644 index 0000000..9f28af2 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Dept.java @@ -0,0 +1,86 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.domain; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseEntity; +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Objects; +import java.util.Set; + +/** +* @author Zheng Jie +* @date 2019-03-25 +*/ +@Entity +@Getter +@Setter +@Table(name="sys_dept") +public class Dept extends BaseEntity implements Serializable { + + @Id + @Column(name = "dept_id") + @NotNull(groups = Update.class) + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @JSONField(serialize = false) + @ManyToMany(mappedBy = "depts") + @ApiModelProperty(value = "角色") + private Set roles; + + @ApiModelProperty(value = "排序") + private Integer deptSort; + + @NotBlank + @ApiModelProperty(value = "部门名称") + private String name; + + @NotNull + @ApiModelProperty(value = "是否启用") + private Boolean enabled; + + @ApiModelProperty(value = "上级部门") + private Long pid; + + @ApiModelProperty(value = "子节点数目", hidden = true) + private Integer subCount = 0; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Dept dept = (Dept) o; + return Objects.equals(id, dept.id) && + Objects.equals(name, dept.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Dict.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Dict.java new file mode 100644 index 0000000..689cf2e --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Dict.java @@ -0,0 +1,54 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseEntity; +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.List; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Entity +@Getter +@Setter +@Table(name="sys_dict") +public class Dict extends BaseEntity implements Serializable { + + @Id + @Column(name = "dict_id") + @NotNull(groups = Update.class) + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToMany(mappedBy = "dict",cascade={CascadeType.PERSIST,CascadeType.REMOVE}) + private List dictDetails; + + @NotBlank + @ApiModelProperty(value = "名称") + private String name; + + @ApiModelProperty(value = "描述") + private String description; +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/DictDetail.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/DictDetail.java new file mode 100644 index 0000000..554dde6 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/DictDetail.java @@ -0,0 +1,56 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseEntity; +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Entity +@Getter +@Setter +@Table(name="sys_dict_detail") +public class DictDetail extends BaseEntity implements Serializable { + + @Id + @Column(name = "detail_id") + @NotNull(groups = Update.class) + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @JoinColumn(name = "dict_id") + @ManyToOne(fetch=FetchType.LAZY) + @ApiModelProperty(value = "字典", hidden = true) + private Dict dict; + + @ApiModelProperty(value = "字典标签") + private String label; + + @ApiModelProperty(value = "字典值") + private String value; + + @ApiModelProperty(value = "排序") + private Integer dictSort = 999; +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Job.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Job.java new file mode 100644 index 0000000..f2d358a --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Job.java @@ -0,0 +1,73 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseEntity; +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Objects; + +/** +* @author Zheng Jie +* @date 2019-03-29 +*/ +@Entity +@Getter +@Setter +@Table(name="sys_job") +public class Job extends BaseEntity implements Serializable { + + @Id + @Column(name = "job_id") + @NotNull(groups = Update.class) + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotBlank + @ApiModelProperty(value = "岗位名称") + private String name; + + @NotNull + @ApiModelProperty(value = "岗位排序") + private Long jobSort; + + @NotNull + @ApiModelProperty(value = "是否启用") + private Boolean enabled; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Job job = (Job) o; + return Objects.equals(id, job.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Menu.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Menu.java new file mode 100644 index 0000000..b2ea225 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Menu.java @@ -0,0 +1,110 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.domain; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseEntity; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Objects; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-12-17 + */ +@Entity +@Getter +@Setter +@Table(name = "sys_menu") +public class Menu extends BaseEntity implements Serializable { + + @Id + @Column(name = "menu_id") + @NotNull(groups = {Update.class}) + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @JSONField(serialize = false) + @ManyToMany(mappedBy = "menus") + @ApiModelProperty(value = "菜单角色") + private Set roles; + + @ApiModelProperty(value = "菜单标题") + private String title; + + @Column(name = "name") + @ApiModelProperty(value = "菜单组件名称") + private String componentName; + + @ApiModelProperty(value = "排序") + private Integer menuSort = 999; + + @ApiModelProperty(value = "组件路径") + private String component; + + @ApiModelProperty(value = "路由地址") + private String path; + + @ApiModelProperty(value = "菜单类型,目录、菜单、按钮") + private Integer type; + + @ApiModelProperty(value = "权限标识") + private String permission; + + @ApiModelProperty(value = "菜单图标") + private String icon; + + @Column(columnDefinition = "bit(1) default 0") + @ApiModelProperty(value = "缓存") + private Boolean cache; + + @Column(columnDefinition = "bit(1) default 0") + @ApiModelProperty(value = "是否隐藏") + private Boolean hidden; + + @ApiModelProperty(value = "上级菜单") + private Long pid; + + @ApiModelProperty(value = "子节点数目", hidden = true) + private Integer subCount = 0; + + @ApiModelProperty(value = "外链菜单") + private Boolean iFrame; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Menu menu = (Menu) o; + return Objects.equals(id, menu.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Role.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Role.java new file mode 100644 index 0000000..8b3ad19 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/Role.java @@ -0,0 +1,99 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.domain; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseEntity; +import me.zhengjie.utils.enums.DataScopeEnum; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Objects; +import java.util.Set; + +/** + * 角色 + * @author Zheng Jie + * @date 2018-11-22 + */ +@Getter +@Setter +@Entity +@Table(name = "sys_role") +public class Role extends BaseEntity implements Serializable { + + @Id + @Column(name = "role_id") + @NotNull(groups = {Update.class}) + @GeneratedValue(strategy = GenerationType.IDENTITY) + @ApiModelProperty(value = "ID", hidden = true) + private Long id; + + @JSONField(serialize = false) + @ManyToMany(mappedBy = "roles") + @ApiModelProperty(value = "用户", hidden = true) + private Set users; + + @ManyToMany + @JoinTable(name = "sys_roles_menus", + joinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")}, + inverseJoinColumns = {@JoinColumn(name = "menu_id",referencedColumnName = "menu_id")}) + @ApiModelProperty(value = "菜单", hidden = true) + private Set menus; + + @ManyToMany + @JoinTable(name = "sys_roles_depts", + joinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")}, + inverseJoinColumns = {@JoinColumn(name = "dept_id",referencedColumnName = "dept_id")}) + @ApiModelProperty(value = "部门", hidden = true) + private Set depts; + + @NotBlank + @ApiModelProperty(value = "名称", hidden = true) + private String name; + + @ApiModelProperty(value = "数据权限,全部 、 本级 、 自定义") + private String dataScope = DataScopeEnum.THIS_LEVEL.getValue(); + + @Column(name = "level") + @ApiModelProperty(value = "级别,数值越小,级别越大") + private Integer level = 3; + + @ApiModelProperty(value = "描述") + private String description; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Role role = (Role) o; + return Objects.equals(id, role.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/User.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/User.java new file mode 100644 index 0000000..c496c91 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/User.java @@ -0,0 +1,129 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.annotation.CheckPwd; +import me.zhengjie.base.BaseEntity; +import javax.persistence.*; +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Null; +import java.io.Serializable; +import java.util.Date; +import java.util.Objects; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-11-22 + */ +@Entity +@Getter +@Setter +@Table(name="sys_user") +public class User extends BaseEntity implements Serializable { + + @Id + @Column(name = "user_id") + @NotNull(groups = Update.class) + @GeneratedValue(strategy = GenerationType.IDENTITY) + @ApiModelProperty(value = "ID", hidden = true) + private Long id; + + @ManyToMany + @ApiModelProperty(value = "用户角色") + @JoinTable(name = "sys_users_roles", + joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "user_id")}, + inverseJoinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")}) + private Set roles; + + @ManyToMany + @ApiModelProperty(value = "用户岗位") + @JoinTable(name = "sys_users_jobs", + joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "user_id")}, + inverseJoinColumns = {@JoinColumn(name = "job_id",referencedColumnName = "job_id")}) + private Set jobs; + + @OneToOne + @JoinColumn(name = "dept_id") + @ApiModelProperty(value = "用户部门") + private Dept dept; + + @NotBlank(groups = Create.class) + @Column(unique = true) + @ApiModelProperty(value = "用户名称") + private String username; + + @NotBlank(groups = Create.class) + @ApiModelProperty(value = "用户昵称") + private String nickName; + + @Email(groups = Create.class) + @NotBlank(groups = Create.class) + @ApiModelProperty(value = "邮箱") + private String email; + + @NotBlank(groups = Create.class) + @ApiModelProperty(value = "电话号码") + private String phone; + + @ApiModelProperty(value = "用户性别") + private String gender; + + @ApiModelProperty(value = "头像真实名称",hidden = true) + private String avatarName; + + @ApiModelProperty(value = "头像存储的路径", hidden = true) + private String avatarPath; + + @NotBlank(groups = Create.class) + @CheckPwd(groups = Create.class) + @ApiModelProperty(value = "密码") + private String password; + + @NotNull(groups = Create.class) + @ApiModelProperty(value = "是否启用") + private Boolean enabled; + + @ApiModelProperty(value = "是否为admin账号", hidden = true) + private Boolean isAdmin = false; + + @Column(name = "pwd_reset_time") + @ApiModelProperty(value = "最后修改密码的时间", hidden = true) + private Date pwdResetTime; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + User user = (User) o; + return Objects.equals(id, user.id) && + Objects.equals(username, user.username); + } + + @Override + public int hashCode() { + return Objects.hash(id, username); + } +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/vo/MenuMetaVo.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/vo/MenuMetaVo.java new file mode 100644 index 0000000..647baa8 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/vo/MenuMetaVo.java @@ -0,0 +1,35 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import java.io.Serializable; + +/** + * @author Zheng Jie + * @date 2018-12-20 + */ +@Data +@AllArgsConstructor +public class MenuMetaVo implements Serializable { + + private String title; + + private String icon; + + private Boolean noCache; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/vo/MenuVo.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/vo/MenuVo.java new file mode 100644 index 0000000..82fc0cc --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/vo/MenuVo.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.domain.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; +import java.io.Serializable; +import java.util.List; + +/** + * 构建前端路由时用到 + * @author Zheng Jie + * @date 2018-12-20 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class MenuVo implements Serializable { + + private String name; + + private String path; + + private Boolean hidden; + + private String redirect; + + private String component; + + private Boolean alwaysShow; + + private MenuMetaVo meta; + + private List children; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/vo/UserPassVo.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/vo/UserPassVo.java new file mode 100644 index 0000000..e92d472 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/domain/vo/UserPassVo.java @@ -0,0 +1,37 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.domain.vo; + +import lombok.Data; +import me.zhengjie.annotation.CheckPwd; + +import javax.validation.constraints.NotBlank; + +/** + * 修改密码的 Vo 类 + * @author Zheng Jie + * @date 2019年7月11日13:59:49 + */ +@Data +public class UserPassVo { + + private String oldPass; + + // 注:这里传的是加密后的字符串 + @NotBlank +// @CheckPwd + private String newPass; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/DeptRepository.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/DeptRepository.java new file mode 100644 index 0000000..9858322 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/DeptRepository.java @@ -0,0 +1,69 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.repository; + +import me.zhengjie.modules.system.domain.Dept; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import java.util.List; +import java.util.Set; + +/** +* @author Zheng Jie +* @date 2019-03-25 +*/ +public interface DeptRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 根据 PID 查询 + * @param id pid + * @return / + */ + List findByPid(Long id); + + /** + * 获取顶级部门 + * @return / + */ + List findByPidIsNull(); + + /** + * 根据角色ID 查询 + * @param roleId 角色ID + * @return / + */ + @Query(value = "select d.* from sys_dept d, sys_roles_depts r where " + + "d.dept_id = r.dept_id and r.role_id = ?1", nativeQuery = true) + Set findByRoleId(Long roleId); + + /** + * 判断是否存在子节点 + * @param pid / + * @return / + */ + int countByPid(Long pid); + + /** + * 根据ID更新sub_count + * @param count / + * @param id / + */ + @Modifying + @Query(value = " update sys_dept set sub_count = ?1 where dept_id = ?2 ",nativeQuery = true) + void updateSubCntById(Integer count, Long id); +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/DictDetailRepository.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/DictDetailRepository.java new file mode 100644 index 0000000..d80b970 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/DictDetailRepository.java @@ -0,0 +1,36 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.repository; + +import me.zhengjie.modules.system.domain.DictDetail; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +public interface DictDetailRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 根据字典名称查询 + * @param name / + * @return / + */ + List findByDictName(String name); +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/DictRepository.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/DictRepository.java new file mode 100644 index 0000000..f09b6d1 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/DictRepository.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.repository; + +import me.zhengjie.modules.system.domain.Dict; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; +import java.util.Set; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +public interface DictRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 删除 + * @param ids / + */ + void deleteByIdIn(Set ids); + + /** + * 查询 + * @param ids / + * @return / + */ + List findByIdIn(Set ids); +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/JobRepository.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/JobRepository.java new file mode 100644 index 0000000..e39ebf0 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/JobRepository.java @@ -0,0 +1,42 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.repository; + +import me.zhengjie.modules.system.domain.Job; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.Set; + +/** +* @author Zheng Jie +* @date 2019-03-29 +*/ +public interface JobRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 根据名称查询 + * @param name 名称 + * @return / + */ + Job findByName(String name); + + /** + * 根据Id删除 + * @param ids / + */ + void deleteAllByIdIn(Set ids); +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/MenuRepository.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/MenuRepository.java new file mode 100644 index 0000000..0907606 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/MenuRepository.java @@ -0,0 +1,85 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.repository; + +import me.zhengjie.modules.system.domain.Menu; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-12-17 + */ +public interface MenuRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 根据菜单标题查询 + * @param title 菜单标题 + * @return / + */ + Menu findByTitle(String title); + + /** + * 根据组件名称查询 + * @param name 组件名称 + * @return / + */ + Menu findByComponentName(String name); + + /** + * 根据菜单的 PID 查询 + * @param pid / + * @return / + */ + List findByPid(long pid); + + /** + * 查询顶级菜单 + * @return / + */ + List findByPidIsNull(); + + /** + * 根据角色ID与菜单类型查询菜单 + * @param roleIds roleIDs + * @param type 类型 + * @return / + */ + @Query(value = "SELECT m.* FROM sys_menu m, sys_roles_menus r WHERE " + + "m.menu_id = r.menu_id AND r.role_id IN ?1 AND type != ?2 order by m.menu_sort asc",nativeQuery = true) + LinkedHashSet findByRoleIdsAndTypeNot(Set roleIds, int type); + + /** + * 获取节点数量 + * @param id / + * @return / + */ + int countByPid(Long id); + + /** + * 更新节点数目 + * @param count / + * @param menuId / + */ + @Modifying + @Query(value = " update sys_menu set sub_count = ?1 where menu_id = ?2 ",nativeQuery = true) + void updateSubCntById(int count, Long menuId); +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/RoleRepository.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/RoleRepository.java new file mode 100644 index 0000000..8e76cc5 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/RoleRepository.java @@ -0,0 +1,80 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.repository; + +import me.zhengjie.modules.system.domain.Role; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-12-03 + */ +public interface RoleRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 根据名称查询 + * @param name / + * @return / + */ + Role findByName(String name); + + /** + * 删除多个角色 + * @param ids / + */ + void deleteAllByIdIn(Set ids); + + /** + * 根据用户ID查询 + * @param id 用户ID + * @return / + */ + @Query(value = "SELECT r.* FROM sys_role r, sys_users_roles u WHERE " + + "r.role_id = u.role_id AND u.user_id = ?1",nativeQuery = true) + Set findByUserId(Long id); + + /** + * 解绑角色菜单 + * @param id 菜单ID + */ + @Modifying + @Query(value = "delete from sys_roles_menus where menu_id = ?1",nativeQuery = true) + void untiedMenu(Long id); + + /** + * 根据部门查询 + * @param deptIds / + * @return / + */ + @Query(value = "select count(1) from sys_role r, sys_roles_depts d where " + + "r.role_id = d.role_id and d.dept_id in ?1",nativeQuery = true) + int countByDepts(Set deptIds); + + /** + * 根据菜单Id查询 + * @param menuIds / + * @return / + */ + @Query(value = "SELECT r.* FROM sys_role r, sys_roles_menus m WHERE " + + "r.role_id = m.role_id AND m.menu_id in ?1",nativeQuery = true) + List findInMenuId(List menuIds); +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/UserRepository.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/UserRepository.java new file mode 100644 index 0000000..c5c88a8 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/repository/UserRepository.java @@ -0,0 +1,130 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.repository; + +import me.zhengjie.modules.system.domain.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import java.util.Date; +import java.util.List; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-11-22 + */ +public interface UserRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 根据用户名查询 + * @param username 用户名 + * @return / + */ + User findByUsername(String username); + + /** + * 根据邮箱查询 + * @param email 邮箱 + * @return / + */ + User findByEmail(String email); + + /** + * 根据手机号查询 + * @param phone 手机号 + * @return / + */ + User findByPhone(String phone); + + /** + * 修改密码 + * @param username 用户名 + * @param pass 密码 + * @param lastPasswordResetTime / + */ + @Modifying + @Query(value = "update sys_user set password = ?2 , pwd_reset_time = ?3 where username = ?1",nativeQuery = true) + void updatePass(String username, String pass, Date lastPasswordResetTime); + + /** + * 修改邮箱 + * @param username 用户名 + * @param email 邮箱 + */ + @Modifying + @Query(value = "update sys_user set email = ?2 where username = ?1",nativeQuery = true) + void updateEmail(String username, String email); + + /** + * 根据角色查询用户 + * @param roleId / + * @return / + */ + @Query(value = "SELECT u.* FROM sys_user u, sys_users_roles r WHERE" + + " u.user_id = r.user_id AND r.role_id = ?1", nativeQuery = true) + List findByRoleId(Long roleId); + + /** + * 根据角色中的部门查询 + * @param deptId / + * @return / + */ + @Query(value = "SELECT u.* FROM sys_user u, sys_users_roles r, sys_roles_depts d WHERE " + + "u.user_id = r.user_id AND r.role_id = d.role_id AND d.dept_id = ?1 group by u.user_id", nativeQuery = true) + List findByRoleDeptId(Long deptId); + + /** + * 根据菜单查询 + * @param id 菜单ID + * @return / + */ + @Query(value = "SELECT u.* FROM sys_user u, sys_users_roles ur, sys_roles_menus rm WHERE\n" + + "u.user_id = ur.user_id AND ur.role_id = rm.role_id AND rm.menu_id = ?1 group by u.user_id", nativeQuery = true) + List findByMenuId(Long id); + + /** + * 根据Id删除 + * @param ids / + */ + void deleteAllByIdIn(Set ids); + + /** + * 根据岗位查询 + * @param ids / + * @return / + */ + @Query(value = "SELECT count(1) FROM sys_user u, sys_users_jobs j WHERE u.user_id = j.user_id AND j.job_id IN ?1", nativeQuery = true) + int countByJobs(Set ids); + + /** + * 根据部门查询 + * @param deptIds / + * @return / + */ + @Query(value = "SELECT count(1) FROM sys_user u WHERE u.dept_id IN ?1", nativeQuery = true) + int countByDepts(Set deptIds); + + /** + * 根据角色查询 + * @param ids / + * @return / + */ + @Query(value = "SELECT count(1) FROM sys_user u, sys_users_roles r WHERE " + + "u.user_id = r.user_id AND r.role_id in ?1", nativeQuery = true) + int countByRoles(Set ids); +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/DeptController.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/DeptController.java new file mode 100644 index 0000000..9b3b0ef --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/DeptController.java @@ -0,0 +1,117 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.rest; + +import cn.hutool.core.collection.CollectionUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.Log; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.system.domain.Dept; +import me.zhengjie.modules.system.service.DeptService; +import me.zhengjie.modules.system.service.dto.DeptDto; +import me.zhengjie.modules.system.service.dto.DeptQueryCriteria; +import me.zhengjie.utils.PageUtil; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.util.*; + +/** +* @author Zheng Jie +* @date 2019-03-25 +*/ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:部门管理") +@RequestMapping("/api/dept") +public class DeptController { + + private final DeptService deptService; + private static final String ENTITY_NAME = "dept"; + + @ApiOperation("导出部门数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('dept:list')") + public void download(HttpServletResponse response, DeptQueryCriteria criteria) throws Exception { + deptService.download(deptService.queryAll(criteria, false), response); + } + + @ApiOperation("查询部门") + @GetMapping + @PreAuthorize("@el.check('user:list','dept:list')") + public ResponseEntity query(DeptQueryCriteria criteria) throws Exception { + List deptDtos = deptService.queryAll(criteria, true); + return new ResponseEntity<>(PageUtil.toPage(deptDtos, deptDtos.size()),HttpStatus.OK); + } + + @ApiOperation("查询部门:根据ID获取同级与上级数据") + @PostMapping("/superior") + @PreAuthorize("@el.check('user:list','dept:list')") + public ResponseEntity getSuperior(@RequestBody List ids) { + Set deptDtos = new LinkedHashSet<>(); + for (Long id : ids) { + DeptDto deptDto = deptService.findById(id); + List depts = deptService.getSuperior(deptDto, new ArrayList<>()); + deptDtos.addAll(depts); + } + return new ResponseEntity<>(deptService.buildTree(new ArrayList<>(deptDtos)),HttpStatus.OK); + } + + @Log("新增部门") + @ApiOperation("新增部门") + @PostMapping + @PreAuthorize("@el.check('dept:add')") + public ResponseEntity create(@Validated @RequestBody Dept resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + deptService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改部门") + @ApiOperation("修改部门") + @PutMapping + @PreAuthorize("@el.check('dept:edit')") + public ResponseEntity update(@Validated(Dept.Update.class) @RequestBody Dept resources){ + deptService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除部门") + @ApiOperation("删除部门") + @DeleteMapping + @PreAuthorize("@el.check('dept:del')") + public ResponseEntity delete(@RequestBody Set ids){ + Set deptDtos = new HashSet<>(); + for (Long id : ids) { + List deptList = deptService.findByPid(id); + deptDtos.add(deptService.findById(id)); + if(CollectionUtil.isNotEmpty(deptList)){ + deptDtos = deptService.getDeleteDepts(deptList, deptDtos); + } + } + // 验证是否被角色或用户关联 + deptService.verification(deptDtos); + deptService.delete(deptDtos); + return new ResponseEntity<>(HttpStatus.OK); + } +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/DictController.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/DictController.java new file mode 100644 index 0000000..f1e4d58 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/DictController.java @@ -0,0 +1,99 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.Log; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.system.domain.Dict; +import me.zhengjie.modules.system.service.DictService; +import me.zhengjie.modules.system.service.dto.DictQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Set; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:字典管理") +@RequestMapping("/api/dict") +public class DictController { + + private final DictService dictService; + private static final String ENTITY_NAME = "dict"; + + @ApiOperation("导出字典数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('dict:list')") + public void download(HttpServletResponse response, DictQueryCriteria criteria) throws IOException { + dictService.download(dictService.queryAll(criteria), response); + } + + @ApiOperation("查询字典") + @GetMapping(value = "/all") + @PreAuthorize("@el.check('dict:list')") + public ResponseEntity queryAll(){ + return new ResponseEntity<>(dictService.queryAll(new DictQueryCriteria()),HttpStatus.OK); + } + + @ApiOperation("查询字典") + @GetMapping + @PreAuthorize("@el.check('dict:list')") + public ResponseEntity query(DictQueryCriteria resources, Pageable pageable){ + return new ResponseEntity<>(dictService.queryAll(resources,pageable),HttpStatus.OK); + } + + @Log("新增字典") + @ApiOperation("新增字典") + @PostMapping + @PreAuthorize("@el.check('dict:add')") + public ResponseEntity create(@Validated @RequestBody Dict resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + dictService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改字典") + @ApiOperation("修改字典") + @PutMapping + @PreAuthorize("@el.check('dict:edit')") + public ResponseEntity update(@Validated(Dict.Update.class) @RequestBody Dict resources){ + dictService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除字典") + @ApiOperation("删除字典") + @DeleteMapping + @PreAuthorize("@el.check('dict:del')") + public ResponseEntity delete(@RequestBody Set ids){ + dictService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/DictDetailController.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/DictDetailController.java new file mode 100644 index 0000000..92f65fd --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/DictDetailController.java @@ -0,0 +1,99 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.Log; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.system.domain.DictDetail; +import me.zhengjie.modules.system.service.DictDetailService; +import me.zhengjie.modules.system.service.dto.DictDetailDto; +import me.zhengjie.modules.system.service.dto.DictDetailQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:字典详情管理") +@RequestMapping("/api/dictDetail") +public class DictDetailController { + + private final DictDetailService dictDetailService; + private static final String ENTITY_NAME = "dictDetail"; + + @ApiOperation("查询字典详情") + @GetMapping + public ResponseEntity query(DictDetailQueryCriteria criteria, + @PageableDefault(sort = {"dictSort"}, direction = Sort.Direction.ASC) Pageable pageable){ + return new ResponseEntity<>(dictDetailService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @ApiOperation("查询多个字典详情") + @GetMapping(value = "/map") + public ResponseEntity getDictDetailMaps(@RequestParam String dictName){ + String[] names = dictName.split("[,,]"); + Map> dictMap = new HashMap<>(16); + for (String name : names) { + dictMap.put(name, dictDetailService.getDictByName(name)); + } + return new ResponseEntity<>(dictMap, HttpStatus.OK); + } + + @Log("新增字典详情") + @ApiOperation("新增字典详情") + @PostMapping + @PreAuthorize("@el.check('dict:add')") + public ResponseEntity create(@Validated @RequestBody DictDetail resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + dictDetailService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改字典详情") + @ApiOperation("修改字典详情") + @PutMapping + @PreAuthorize("@el.check('dict:edit')") + public ResponseEntity update(@Validated(DictDetail.Update.class) @RequestBody DictDetail resources){ + dictDetailService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除字典详情") + @ApiOperation("删除字典详情") + @DeleteMapping(value = "/{id}") + @PreAuthorize("@el.check('dict:del')") + public ResponseEntity delete(@PathVariable Long id){ + dictDetailService.delete(id); + return new ResponseEntity<>(HttpStatus.OK); + } +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/JobController.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/JobController.java new file mode 100644 index 0000000..cac14c0 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/JobController.java @@ -0,0 +1,94 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.Log; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.system.domain.Job; +import me.zhengjie.modules.system.service.JobService; +import me.zhengjie.modules.system.service.dto.JobQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Set; + +/** +* @author Zheng Jie +* @date 2019-03-29 +*/ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:岗位管理") +@RequestMapping("/api/job") +public class JobController { + + private final JobService jobService; + private static final String ENTITY_NAME = "job"; + + @ApiOperation("导出岗位数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('job:list')") + public void download(HttpServletResponse response, JobQueryCriteria criteria) throws IOException { + jobService.download(jobService.queryAll(criteria), response); + } + + @ApiOperation("查询岗位") + @GetMapping + @PreAuthorize("@el.check('job:list','user:list')") + public ResponseEntity query(JobQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(jobService.queryAll(criteria, pageable),HttpStatus.OK); + } + + @Log("新增岗位") + @ApiOperation("新增岗位") + @PostMapping + @PreAuthorize("@el.check('job:add')") + public ResponseEntity create(@Validated @RequestBody Job resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + jobService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改岗位") + @ApiOperation("修改岗位") + @PutMapping + @PreAuthorize("@el.check('job:edit')") + public ResponseEntity update(@Validated(Job.Update.class) @RequestBody Job resources){ + jobService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除岗位") + @ApiOperation("删除岗位") + @DeleteMapping + @PreAuthorize("@el.check('job:del')") + public ResponseEntity delete(@RequestBody Set ids){ + // 验证是否被用户关联 + jobService.verification(ids); + jobService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/LimitController.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/LimitController.java new file mode 100644 index 0000000..329c5ac --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/LimitController.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import me.zhengjie.annotation.Limit; +import me.zhengjie.annotation.rest.AnonymousGetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author / + * 接口限流测试类 + */ +@RestController +@RequestMapping("/api/limit") +@Api(tags = "系统:限流测试管理") +public class LimitController { + + private static final AtomicInteger ATOMIC_INTEGER = new AtomicInteger(); + + /** + * 测试限流注解,下面配置说明该接口 60秒内最多只能访问 10次,保存到redis的键名为 limit_test, + */ + @AnonymousGetMapping + @ApiOperation("测试") + @Limit(key = "test", period = 60, count = 10, name = "testLimit", prefix = "limit") + public int test() { + return ATOMIC_INTEGER.incrementAndGet(); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/MenuController.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/MenuController.java new file mode 100644 index 0000000..d5461a2 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/MenuController.java @@ -0,0 +1,147 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.rest; + +import cn.hutool.core.collection.CollectionUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.Log; +import me.zhengjie.modules.system.domain.Menu; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.system.service.MenuService; +import me.zhengjie.modules.system.service.dto.MenuDto; +import me.zhengjie.modules.system.service.dto.MenuQueryCriteria; +import me.zhengjie.modules.system.service.mapstruct.MenuMapper; +import me.zhengjie.utils.PageUtil; +import me.zhengjie.utils.SecurityUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Zheng Jie + * @date 2018-12-03 + */ + +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:菜单管理") +@RequestMapping("/api/menus") +public class MenuController { + + private final MenuService menuService; + private final MenuMapper menuMapper; + private static final String ENTITY_NAME = "menu"; + + @ApiOperation("导出菜单数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('menu:list')") + public void download(HttpServletResponse response, MenuQueryCriteria criteria) throws Exception { + menuService.download(menuService.queryAll(criteria, false), response); + } + + @GetMapping(value = "/build") + @ApiOperation("获取前端所需菜单") + public ResponseEntity buildMenus(){ + List menuDtoList = menuService.findByUser(SecurityUtils.getCurrentUserId()); + List menuDtos = menuService.buildTree(menuDtoList); + return new ResponseEntity<>(menuService.buildMenus(menuDtos),HttpStatus.OK); + } + + @ApiOperation("返回全部的菜单") + @GetMapping(value = "/lazy") + @PreAuthorize("@el.check('menu:list','roles:list')") + public ResponseEntity query(@RequestParam Long pid){ + return new ResponseEntity<>(menuService.getMenus(pid),HttpStatus.OK); + } + + @ApiOperation("根据菜单ID返回所有子节点ID,包含自身ID") + @GetMapping(value = "/child") + @PreAuthorize("@el.check('menu:list','roles:list')") + public ResponseEntity child(@RequestParam Long id){ + Set menuSet = new HashSet<>(); + List menuList = menuService.getMenus(id); + menuSet.add(menuService.findOne(id)); + menuSet = menuService.getChildMenus(menuMapper.toEntity(menuList), menuSet); + Set ids = menuSet.stream().map(Menu::getId).collect(Collectors.toSet()); + return new ResponseEntity<>(ids,HttpStatus.OK); + } + + @GetMapping + @ApiOperation("查询菜单") + @PreAuthorize("@el.check('menu:list')") + public ResponseEntity query(MenuQueryCriteria criteria) throws Exception { + List menuDtoList = menuService.queryAll(criteria, true); + return new ResponseEntity<>(PageUtil.toPage(menuDtoList, menuDtoList.size()),HttpStatus.OK); + } + + @ApiOperation("查询菜单:根据ID获取同级与上级数据") + @PostMapping("/superior") + @PreAuthorize("@el.check('menu:list')") + public ResponseEntity getSuperior(@RequestBody List ids) { + Set menuDtos = new LinkedHashSet<>(); + if(CollectionUtil.isNotEmpty(ids)){ + for (Long id : ids) { + MenuDto menuDto = menuService.findById(id); + menuDtos.addAll(menuService.getSuperior(menuDto, new ArrayList<>())); + } + return new ResponseEntity<>(menuService.buildTree(new ArrayList<>(menuDtos)),HttpStatus.OK); + } + return new ResponseEntity<>(menuService.getMenus(null),HttpStatus.OK); + } + + @Log("新增菜单") + @ApiOperation("新增菜单") + @PostMapping + @PreAuthorize("@el.check('menu:add')") + public ResponseEntity create(@Validated @RequestBody Menu resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + menuService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改菜单") + @ApiOperation("修改菜单") + @PutMapping + @PreAuthorize("@el.check('menu:edit')") + public ResponseEntity update(@Validated(Menu.Update.class) @RequestBody Menu resources){ + menuService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除菜单") + @ApiOperation("删除菜单") + @DeleteMapping + @PreAuthorize("@el.check('menu:del')") + public ResponseEntity delete(@RequestBody Set ids){ + Set menuSet = new HashSet<>(); + for (Long id : ids) { + List menuList = menuService.getMenus(id); + menuSet.add(menuService.findOne(id)); + menuSet = menuService.getChildMenus(menuMapper.toEntity(menuList), menuSet); + } + menuService.delete(menuSet); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/MonitorController.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/MonitorController.java new file mode 100644 index 0000000..35ac0c5 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/MonitorController.java @@ -0,0 +1,45 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.modules.system.service.MonitorService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +/** + * @author Zheng Jie + * @date 2020-05-02 + */ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统-服务监控管理") +@RequestMapping("/api/monitor") +public class MonitorController { + + private final MonitorService serverService; + + @GetMapping + @ApiOperation("查询服务监控") + @PreAuthorize("@el.check('monitor:list')") + public ResponseEntity query(){ + return new ResponseEntity<>(serverService.getServers(),HttpStatus.OK); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/RoleController.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/RoleController.java new file mode 100644 index 0000000..a1edc93 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/RoleController.java @@ -0,0 +1,154 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.rest; + +import cn.hutool.core.lang.Dict; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.Log; +import me.zhengjie.modules.system.domain.Role; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.system.service.RoleService; +import me.zhengjie.modules.system.service.dto.RoleDto; +import me.zhengjie.modules.system.service.dto.RoleQueryCriteria; +import me.zhengjie.modules.system.service.dto.RoleSmallDto; +import me.zhengjie.utils.SecurityUtils; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author Zheng Jie + * @date 2018-12-03 + */ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:角色管理") +@RequestMapping("/api/roles") +public class RoleController { + + private final RoleService roleService; + + private static final String ENTITY_NAME = "role"; + + @ApiOperation("获取单个role") + @GetMapping(value = "/{id}") + @PreAuthorize("@el.check('roles:list')") + public ResponseEntity query(@PathVariable Long id){ + return new ResponseEntity<>(roleService.findById(id), HttpStatus.OK); + } + + @ApiOperation("导出角色数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('role:list')") + public void download(HttpServletResponse response, RoleQueryCriteria criteria) throws IOException { + roleService.download(roleService.queryAll(criteria), response); + } + + @ApiOperation("返回全部的角色") + @GetMapping(value = "/all") + @PreAuthorize("@el.check('roles:list','user:add','user:edit')") + public ResponseEntity query(){ + return new ResponseEntity<>(roleService.queryAll(),HttpStatus.OK); + } + + @ApiOperation("查询角色") + @GetMapping + @PreAuthorize("@el.check('roles:list')") + public ResponseEntity query(RoleQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(roleService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @ApiOperation("获取用户级别") + @GetMapping(value = "/level") + public ResponseEntity getLevel(){ + return new ResponseEntity<>(Dict.create().set("level", getLevels(null)),HttpStatus.OK); + } + + @Log("新增角色") + @ApiOperation("新增角色") + @PostMapping + @PreAuthorize("@el.check('roles:add')") + public ResponseEntity create(@Validated @RequestBody Role resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + getLevels(resources.getLevel()); + roleService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改角色") + @ApiOperation("修改角色") + @PutMapping + @PreAuthorize("@el.check('roles:edit')") + public ResponseEntity update(@Validated(Role.Update.class) @RequestBody Role resources){ + getLevels(resources.getLevel()); + roleService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("修改角色菜单") + @ApiOperation("修改角色菜单") + @PutMapping(value = "/menu") + @PreAuthorize("@el.check('roles:edit')") + public ResponseEntity updateMenu(@RequestBody Role resources){ + RoleDto role = roleService.findById(resources.getId()); + getLevels(role.getLevel()); + roleService.updateMenu(resources,role); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除角色") + @ApiOperation("删除角色") + @DeleteMapping + @PreAuthorize("@el.check('roles:del')") + public ResponseEntity delete(@RequestBody Set ids){ + for (Long id : ids) { + RoleDto role = roleService.findById(id); + getLevels(role.getLevel()); + } + // 验证是否被用户关联 + roleService.verification(ids); + roleService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + /** + * 获取用户的角色级别 + * @return / + */ + private int getLevels(Integer level){ + List levels = roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList()); + int min = Collections.min(levels); + if(level != null){ + if(level < min){ + throw new BadRequestException("权限不足,你的角色级别:" + min + ",低于操作的角色级别:" + level); + } + } + return min; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/UserController.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/UserController.java new file mode 100644 index 0000000..a5e6dca --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/UserController.java @@ -0,0 +1,230 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.rest; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.annotation.Log; +import me.zhengjie.base.BaseEntity; +import me.zhengjie.config.RsaProperties; +import me.zhengjie.dto.Dto; +import me.zhengjie.modules.system.domain.Dept; +import me.zhengjie.modules.system.service.DataService; +import me.zhengjie.modules.system.domain.User; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.system.domain.vo.UserPassVo; +import me.zhengjie.modules.system.service.DeptService; +import me.zhengjie.modules.system.service.RoleService; +import me.zhengjie.modules.system.service.dto.RoleSmallDto; +import me.zhengjie.modules.system.service.dto.UserDto; +import me.zhengjie.modules.system.service.dto.UserQueryCriteria; +import me.zhengjie.modules.system.service.VerifyService; +import me.zhengjie.utils.*; +import me.zhengjie.modules.system.service.UserService; +import me.zhengjie.utils.enums.CodeEnum; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Api(tags = "系统:用户管理") +@RestController +@RequestMapping("/api/users") +@RequiredArgsConstructor +public class UserController { + + private final PasswordEncoder passwordEncoder; + private final UserService userService; + private final DataService dataService; + private final DeptService deptService; + private final RoleService roleService; + private final VerifyService verificationCodeService; + private final RedisUtils redisUtils; + + @ApiOperation("导出用户数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('user:list')") + public void download(HttpServletResponse response, UserQueryCriteria criteria) throws IOException { + userService.download(userService.queryAll(criteria), response); + } + + @ApiOperation("查询用户") + @GetMapping + @PreAuthorize("@el.check('user:list')") + public ResponseEntity query(UserQueryCriteria criteria, Pageable pageable){ + if (!ObjectUtils.isEmpty(criteria.getDeptId())) { + criteria.getDeptIds().add(criteria.getDeptId()); + // 先查找是否存在子节点 + List data = deptService.findByPid(criteria.getDeptId()); + // 然后把子节点的ID都加入到集合中 + criteria.getDeptIds().addAll(deptService.getDeptChildren(data)); + } + // 数据权限 + List dataScopes = dataService.getDeptIds(userService.findByName(SecurityUtils.getCurrentUsername())); + // criteria.getDeptIds() 不为空并且数据权限不为空则取交集 + if (!CollectionUtils.isEmpty(criteria.getDeptIds()) && !CollectionUtils.isEmpty(dataScopes)){ + // 取交集 + criteria.getDeptIds().retainAll(dataScopes); + if(!CollectionUtil.isEmpty(criteria.getDeptIds())){ + return new ResponseEntity<>(userService.queryAll(criteria,pageable),HttpStatus.OK); + } + } else { + // 否则取并集 + criteria.getDeptIds().addAll(dataScopes); + return new ResponseEntity<>(userService.queryAll(criteria,pageable),HttpStatus.OK); + } + return new ResponseEntity<>(PageUtil.toPage(null,0),HttpStatus.OK); + } + + /** + * 解冻账号 + * @author: zeng + */ + @GetMapping("/unfreeze") + @PreAuthorize("@el.check('user:list')") + public Dto unfreeze(String username) { + if (ObjectUtil.isEmpty(username)) { + return Dto.returnResult(null); + } + String key = String.format(RedisUtils.BLOCKED_ACCOUNT, username); + redisUtils.del(key); + return Dto.returnResult(true); + } + + @Log("新增用户") + @ApiOperation("新增用户") + @PostMapping + @PreAuthorize("@el.check('user:add')") + public ResponseEntity create(@Validated(BaseEntity.Create.class) @RequestBody User resources){ + checkLevel(resources); + // 默认密码 123456 + resources.setPassword(passwordEncoder.encode(resources.getPassword())); + userService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改用户") + @ApiOperation("修改用户") + @PutMapping + @PreAuthorize("@el.check('user:edit')") + public ResponseEntity update(@Validated(User.Update.class) @RequestBody User resources) throws Exception { + checkLevel(resources); + userService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("修改用户:个人中心") + @ApiOperation("修改用户:个人中心") + @PutMapping(value = "center") + public ResponseEntity center(@Validated(User.Update.class) @RequestBody User resources){ + if(!resources.getId().equals(SecurityUtils.getCurrentUserId())){ + throw new BadRequestException("不能修改他人资料"); + } + userService.updateCenter(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除用户") + @ApiOperation("删除用户") + @DeleteMapping + @PreAuthorize("@el.check('user:del')") + public ResponseEntity delete(@RequestBody Set ids){ + for (Long id : ids) { + Integer currentLevel = Collections.min(roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList())); + Integer optLevel = Collections.min(roleService.findByUsersId(id).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList())); + if (currentLevel > optLevel) { + throw new BadRequestException("角色权限不足,不能删除:" + userService.findById(id).getUsername()); + } + } + userService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + /** + * 修改密码 + * @param passVo 修改密码DTO + * @return + * @throws Exception + */ + @ApiOperation("修改密码") + @PostMapping(value = "/updatePass") + public ResponseEntity updatePass(@RequestBody @Validated UserPassVo passVo) throws Exception { + String oldPass = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,passVo.getOldPass()); + String newPass = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,passVo.getNewPass()); + UserDto user = userService.findByName(SecurityUtils.getCurrentUsername()); + if(!passwordEncoder.matches(oldPass, user.getPassword())){ + throw new BadRequestException("修改失败,旧密码错误"); + } + if(passwordEncoder.matches(newPass, user.getPassword())){ + throw new BadRequestException("新密码不能与旧密码相同"); + } + if (!Pattern.matches(CheckPwdValidator.p, newPass)) { + throw new BadRequestException("密码格式错误,必须包含大小写字母、数子、英文特殊符号,且长度在16~64之间!"); + } + userService.updatePass(user.getUsername(),passwordEncoder.encode(newPass)); + return new ResponseEntity<>(HttpStatus.OK); + } + + @ApiOperation("修改头像") + @PostMapping(value = "/updateAvatar") + public ResponseEntity updateAvatar(@RequestParam MultipartFile avatar){ + return new ResponseEntity<>(userService.updateAvatar(avatar), HttpStatus.OK); + } + + @Log("修改邮箱") + @ApiOperation("修改邮箱") + @PostMapping(value = "/updateEmail/{code}") + public ResponseEntity updateEmail(@PathVariable String code,@RequestBody User user) throws Exception { + String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,user.getPassword()); + UserDto userDto = userService.findByName(SecurityUtils.getCurrentUsername()); + if(!passwordEncoder.matches(password, userDto.getPassword())){ + throw new BadRequestException("密码错误"); + } + verificationCodeService.validated(CodeEnum.EMAIL_RESET_EMAIL_CODE.getKey() + user.getEmail(), code); + userService.updateEmail(userDto.getUsername(),user.getEmail()); + return new ResponseEntity<>(HttpStatus.OK); + } + + /** + * 如果当前用户的角色级别低于创建用户的角色级别,则抛出权限不足的错误 + * @param resources / + */ + private void checkLevel(User resources) { + Integer currentLevel = Collections.min(roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList())); + Integer optLevel = roleService.findByRoles(resources.getRoles()); + if (currentLevel > optLevel) { + throw new BadRequestException("角色权限不足"); + } + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/VerifyController.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/VerifyController.java new file mode 100644 index 0000000..09ba44b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/rest/VerifyController.java @@ -0,0 +1,76 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.zhengjie.domain.vo.EmailVo; +import me.zhengjie.service.EmailService; +import me.zhengjie.modules.system.service.VerifyService; +import me.zhengjie.utils.enums.CodeBiEnum; +import me.zhengjie.utils.enums.CodeEnum; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import java.util.Objects; + +/** + * @author Zheng Jie + * @date 2018-12-26 + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/code") +@Api(tags = "系统:验证码管理") +public class VerifyController { + + private final VerifyService verificationCodeService; + private final EmailService emailService; + + @PostMapping(value = "/resetEmail") + @ApiOperation("重置邮箱,发送验证码") + public ResponseEntity resetEmail(@RequestParam String email){ + EmailVo emailVo = verificationCodeService.sendEmail(email, CodeEnum.EMAIL_RESET_EMAIL_CODE.getKey()); + emailService.send(emailVo,emailService.find()); + return new ResponseEntity<>(HttpStatus.OK); + } + + @PostMapping(value = "/email/resetPass") + @ApiOperation("重置密码,发送验证码") + public ResponseEntity resetPass(@RequestParam String email){ + EmailVo emailVo = verificationCodeService.sendEmail(email, CodeEnum.EMAIL_RESET_PWD_CODE.getKey()); + emailService.send(emailVo,emailService.find()); + return new ResponseEntity<>(HttpStatus.OK); + } + + @GetMapping(value = "/validated") + @ApiOperation("验证码验证") + public ResponseEntity validated(@RequestParam String email, @RequestParam String code, @RequestParam Integer codeBi){ + CodeBiEnum biEnum = CodeBiEnum.find(codeBi); + switch (Objects.requireNonNull(biEnum)){ + case ONE: + verificationCodeService.validated(CodeEnum.EMAIL_RESET_EMAIL_CODE.getKey() + email ,code); + break; + case TWO: + verificationCodeService.validated(CodeEnum.EMAIL_RESET_PWD_CODE.getKey() + email ,code); + break; + default: + break; + } + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/DataService.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/DataService.java new file mode 100644 index 0000000..10258d9 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/DataService.java @@ -0,0 +1,34 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service; + +import me.zhengjie.modules.system.service.dto.UserDto; +import java.util.List; + +/** + * 数据权限服务类 + * @author Zheng Jie + * @date 2020-05-07 + */ +public interface DataService { + + /** + * 获取数据权限 + * @param user / + * @return / + */ + List getDeptIds(UserDto user); +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/DeptService.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/DeptService.java new file mode 100644 index 0000000..d589bf8 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/DeptService.java @@ -0,0 +1,124 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service; + +import me.zhengjie.modules.system.domain.Dept; +import me.zhengjie.modules.system.service.dto.DeptDto; +import me.zhengjie.modules.system.service.dto.DeptQueryCriteria; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** +* @author Zheng Jie +* @date 2019-03-25 +*/ +public interface DeptService { + + /** + * 查询所有数据 + * @param criteria 条件 + * @param isQuery / + * @throws Exception / + * @return / + */ + List queryAll(DeptQueryCriteria criteria, Boolean isQuery) throws Exception; + + /** + * 根据ID查询 + * @param id / + * @return / + */ + DeptDto findById(Long id); + + /** + * 创建 + * @param resources / + */ + void create(Dept resources); + + /** + * 编辑 + * @param resources / + */ + void update(Dept resources); + + /** + * 删除 + * @param deptDtos / + * + */ + void delete(Set deptDtos); + + /** + * 根据PID查询 + * @param pid / + * @return / + */ + List findByPid(long pid); + + /** + * 根据角色ID查询 + * @param id / + * @return / + */ + Set findByRoleId(Long id); + + /** + * 导出数据 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; + + /** + * 获取待删除的部门 + * @param deptList / + * @param deptDtos / + * @return / + */ + Set getDeleteDepts(List deptList, Set deptDtos); + + /** + * 根据ID获取同级与上级数据 + * @param deptDto / + * @param depts / + * @return / + */ + List getSuperior(DeptDto deptDto, List depts); + + /** + * 构建树形数据 + * @param deptDtos / + * @return / + */ + Object buildTree(List deptDtos); + + /** + * 获取 + * @param deptList + * @return + */ + List getDeptChildren(List deptList); + + /** + * 验证是否被角色或用户关联 + * @param deptDtos / + */ + void verification(Set deptDtos); +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/DictDetailService.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/DictDetailService.java new file mode 100644 index 0000000..3912a47 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/DictDetailService.java @@ -0,0 +1,63 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service; + +import me.zhengjie.modules.system.domain.DictDetail; +import me.zhengjie.modules.system.service.dto.DictDetailDto; +import me.zhengjie.modules.system.service.dto.DictDetailQueryCriteria; +import org.springframework.data.domain.Pageable; +import java.util.List; +import java.util.Map; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +public interface DictDetailService { + + /** + * 创建 + * @param resources / + */ + void create(DictDetail resources); + + /** + * 编辑 + * @param resources / + */ + void update(DictDetail resources); + + /** + * 删除 + * @param id / + */ + void delete(Long id); + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Map queryAll(DictDetailQueryCriteria criteria, Pageable pageable); + + /** + * 根据字典名称获取字典详情 + * @param name 字典名称 + * @return / + */ + List getDictByName(String name); +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/DictService.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/DictService.java new file mode 100644 index 0000000..9a89e4c --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/DictService.java @@ -0,0 +1,75 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service; + +import me.zhengjie.modules.system.domain.Dict; +import me.zhengjie.modules.system.service.dto.DictDto; +import me.zhengjie.modules.system.service.dto.DictQueryCriteria; +import org.springframework.data.domain.Pageable; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +public interface DictService { + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Map queryAll(DictQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部数据 + * @param dict / + * @return / + */ + List queryAll(DictQueryCriteria dict); + + /** + * 创建 + * @param resources / + * @return / + */ + void create(Dict resources); + + /** + * 编辑 + * @param resources / + */ + void update(Dict resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 导出数据 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/JobService.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/JobService.java new file mode 100644 index 0000000..21c1c98 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/JobService.java @@ -0,0 +1,93 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service; + +import me.zhengjie.modules.system.domain.Job; +import me.zhengjie.modules.system.service.dto.JobDto; +import me.zhengjie.modules.system.service.dto.JobQueryCriteria; +import org.springframework.data.domain.Pageable; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** +* @author Zheng Jie +* @date 2019-03-29 +*/ +public interface JobService { + + /** + * 根据ID查询 + * @param id / + * @return / + */ + JobDto findById(Long id); + + /** + * 创建 + * @param resources / + * @return / + */ + void create(Job resources); + + /** + * 编辑 + * @param resources / + */ + void update(Job resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 删除 + */ + void delete(); + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Map queryAll(JobQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部数据 + * @param criteria / + * @return / + */ + List queryAll(JobQueryCriteria criteria); + + /** + * 导出数据 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; + + /** + * 验证是否被用户关联 + * @param ids / + */ + void verification(Set ids); +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/MenuService.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/MenuService.java new file mode 100644 index 0000000..f7b8ece --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/MenuService.java @@ -0,0 +1,125 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service; + +import me.zhengjie.modules.system.domain.Menu; +import me.zhengjie.modules.system.service.dto.MenuDto; +import me.zhengjie.modules.system.service.dto.MenuQueryCriteria; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-12-17 + */ +public interface MenuService { + + /** + * 查询全部数据 + * @param criteria 条件 + * @param isQuery / + * @throws Exception / + * @return / + */ + List queryAll(MenuQueryCriteria criteria, Boolean isQuery) throws Exception; + + /** + * 根据ID查询 + * @param id / + * @return / + */ + MenuDto findById(long id); + + /** + * 创建 + * @param resources / + */ + void create(Menu resources); + + /** + * 编辑 + * @param resources / + */ + void update(Menu resources); + + /** + * 获取所有子节点,包含自身ID + * @param menuList / + * @param menuSet / + * @return / + */ + Set getChildMenus(List menuList, Set menuSet); + + /** + * 构建菜单树 + * @param menuDtos 原始数据 + * @return / + */ + List buildTree(List menuDtos); + + /** + * 构建菜单树 + * @param menuDtos / + * @return / + */ + Object buildMenus(List menuDtos); + + /** + * 根据ID查询 + * @param id / + * @return / + */ + Menu findOne(Long id); + + /** + * 删除 + * @param menuSet / + */ + void delete(Set menuSet); + + /** + * 导出 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; + + /** + * 懒加载菜单数据 + * @param pid / + * @return / + */ + List getMenus(Long pid); + + /** + * 根据ID获取同级与上级数据 + * @param menuDto / + * @param objects / + * @return / + */ + List getSuperior(MenuDto menuDto, List objects); + + /** + * 根据当前用户获取菜单 + * @param currentUserId / + * @return / + */ + List findByUser(Long currentUserId); +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/MonitorService.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/MonitorService.java new file mode 100644 index 0000000..478225a --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/MonitorService.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service; + +import java.util.Map; + +/** + * @author Zheng Jie + * @date 2020-05-02 + */ +public interface MonitorService { + + /** + * 查询数据分页 + * @return Map + */ + Map getServers(); +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/RoleService.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/RoleService.java new file mode 100644 index 0000000..65e4f58 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/RoleService.java @@ -0,0 +1,136 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service; + +import me.zhengjie.modules.system.domain.Role; +import me.zhengjie.modules.system.service.dto.RoleDto; +import me.zhengjie.modules.system.service.dto.RoleQueryCriteria; +import me.zhengjie.modules.system.service.dto.RoleSmallDto; +import me.zhengjie.modules.system.service.dto.UserDto; +import org.springframework.data.domain.Pageable; +import org.springframework.security.core.GrantedAuthority; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-12-03 + */ +public interface RoleService { + + /** + * 查询全部数据 + * @return / + */ + List queryAll(); + + /** + * 根据ID查询 + * @param id / + * @return / + */ + RoleDto findById(long id); + + /** + * 创建 + * @param resources / + */ + void create(Role resources); + + /** + * 编辑 + * @param resources / + */ + void update(Role resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 根据用户ID查询 + * @param id 用户ID + * @return / + */ + List findByUsersId(Long id); + + /** + * 根据角色查询角色级别 + * @param roles / + * @return / + */ + Integer findByRoles(Set roles); + + /** + * 修改绑定的菜单 + * @param resources / + * @param roleDTO / + */ + void updateMenu(Role resources, RoleDto roleDTO); + + /** + * 解绑菜单 + * @param id / + */ + void untiedMenu(Long id); + + /** + * 待条件分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(RoleQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部 + * @param criteria 条件 + * @return / + */ + List queryAll(RoleQueryCriteria criteria); + + /** + * 导出数据 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; + + /** + * 获取用户权限信息 + * @param user 用户信息 + * @return 权限信息 + */ + List mapToGrantedAuthorities(UserDto user); + + /** + * 验证是否被用户关联 + * @param ids / + */ + void verification(Set ids); + + /** + * 根据菜单Id查询 + * @param menuIds / + * @return / + */ + List findInMenuId(List menuIds); +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/UserService.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/UserService.java new file mode 100644 index 0000000..814af92 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/UserService.java @@ -0,0 +1,116 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service; + +import me.zhengjie.modules.system.domain.User; +import me.zhengjie.modules.system.service.dto.UserDto; +import me.zhengjie.modules.system.service.dto.UserQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +public interface UserService { + + /** + * 根据ID查询 + * @param id ID + * @return / + */ + UserDto findById(long id); + + /** + * 新增用户 + * @param resources / + */ + void create(User resources); + + /** + * 编辑用户 + * @param resources / + */ + void update(User resources) throws Exception; + + /** + * 删除用户 + * @param ids / + */ + void delete(Set ids); + + /** + * 根据用户名查询 + * @param userName / + * @return / + */ + UserDto findByName(String userName); + + /** + * 修改密码 + * @param username 用户名 + * @param encryptPassword 密码 + */ + void updatePass(String username, String encryptPassword); + + /** + * 修改头像 + * @param file 文件 + * @return / + */ + Map updateAvatar(MultipartFile file); + + /** + * 修改邮箱 + * @param username 用户名 + * @param email 邮箱 + */ + void updateEmail(String username, String email); + + /** + * 查询全部 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(UserQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部不分页 + * @param criteria 条件 + * @return / + */ + List queryAll(UserQueryCriteria criteria); + + /** + * 导出数据 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; + + /** + * 用户自助修改资料 + * @param resources / + */ + void updateCenter(User resources); +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/VerifyService.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/VerifyService.java new file mode 100644 index 0000000..4ca39b9 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/VerifyService.java @@ -0,0 +1,41 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service; + +import me.zhengjie.domain.vo.EmailVo; + +/** + * @author Zheng Jie + * @date 2018-12-26 + */ +public interface VerifyService { + + /** + * 发送验证码 + * @param email / + * @param key / + * @return / + */ + EmailVo sendEmail(String email, String key); + + + /** + * 验证 + * @param code / + * @param key / + */ + void validated(String key, String code); +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DeptDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DeptDto.java new file mode 100644 index 0000000..4c3b12a --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DeptDto.java @@ -0,0 +1,78 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseDTO; +import java.io.Serializable; +import java.util.List; +import java.util.Objects; + +/** +* @author Zheng Jie +* @date 2019-03-25 +*/ +@Getter +@Setter +public class DeptDto extends BaseDTO implements Serializable { + + private Long id; + + private String name; + + private Boolean enabled; + + private Integer deptSort; + + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private List children; + + private Long pid; + + private Integer subCount; + + public Boolean getHasChildren() { + return subCount > 0; + } + + public Boolean getLeaf() { + return subCount <= 0; + } + + public String getLabel() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DeptDto deptDto = (DeptDto) o; + return Objects.equals(id, deptDto.id) && + Objects.equals(name, deptDto.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DeptQueryCriteria.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DeptQueryCriteria.java new file mode 100644 index 0000000..4d8cdf2 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DeptQueryCriteria.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import lombok.Data; +import me.zhengjie.annotation.DataPermission; +import me.zhengjie.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** +* @author Zheng Jie +* @date 2019-03-25 +*/ +@Data +@DataPermission(fieldName = "id") +public class DeptQueryCriteria{ + + @Query(type = Query.Type.INNER_LIKE) + private String name; + + @Query + private Boolean enabled; + + @Query + private Long pid; + + @Query(type = Query.Type.IS_NULL, propName = "pid") + private Boolean pidIsNull; + + @Query(type = Query.Type.BETWEEN) + private List createTime; +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DeptSmallDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DeptSmallDto.java new file mode 100644 index 0000000..4dc64e5 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DeptSmallDto.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import lombok.Data; +import java.io.Serializable; + +/** +* @author Zheng Jie +* @date 2019-6-10 16:32:18 +*/ +@Data +public class DeptSmallDto implements Serializable { + + private Long id; + + private String name; +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictDetailDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictDetailDto.java new file mode 100644 index 0000000..a4b931b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictDetailDto.java @@ -0,0 +1,40 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseDTO; +import java.io.Serializable; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Getter +@Setter +public class DictDetailDto extends BaseDTO implements Serializable { + + private Long id; + + private DictSmallDto dict; + + private String label; + + private String value; + + private Integer dictSort; +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictDetailQueryCriteria.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictDetailQueryCriteria.java new file mode 100644 index 0000000..91a01b1 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictDetailQueryCriteria.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import lombok.Data; +import me.zhengjie.annotation.Query; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Data +public class DictDetailQueryCriteria { + + @Query(type = Query.Type.INNER_LIKE) + private String label; + + @Query(propName = "name",joinName = "dict") + private String dictName; +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictDto.java new file mode 100644 index 0000000..048b4a1 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictDto.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseDTO; +import java.io.Serializable; +import java.util.List; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Getter +@Setter +public class DictDto extends BaseDTO implements Serializable { + + private Long id; + + private List dictDetails; + + private String name; + + private String description; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictQueryCriteria.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictQueryCriteria.java new file mode 100644 index 0000000..7207c61 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictQueryCriteria.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import lombok.Data; +import me.zhengjie.annotation.Query; + +/** + * @author Zheng Jie + * 公共查询类 + */ +@Data +public class DictQueryCriteria { + + @Query(blurry = "name,description") + private String blurry; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictSmallDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictSmallDto.java new file mode 100644 index 0000000..98fc6ee --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/DictSmallDto.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import lombok.Getter; +import lombok.Setter; +import java.io.Serializable; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Getter +@Setter +public class DictSmallDto implements Serializable { + + private Long id; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/GoogleAuthCodeDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/GoogleAuthCodeDTO.java new file mode 100644 index 0000000..da99a81 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/GoogleAuthCodeDTO.java @@ -0,0 +1,27 @@ +package me.zhengjie.modules.system.service.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; + +/** + * 验证身份验证码是否正确 DTO + * + * @author rch + * @since 2020-08-25 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class GoogleAuthCodeDTO { + + /** 输入的身份验证码 */ + @NotBlank(message = "身份验证码不能为空") + private String codes; + + /** 密钥 */ + @NotBlank(message = "密钥不能为空") + private String savedSecret; +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/GoogleAuthGenSecretDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/GoogleAuthGenSecretDTO.java new file mode 100644 index 0000000..dd506f4 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/GoogleAuthGenSecretDTO.java @@ -0,0 +1,23 @@ +package me.zhengjie.modules.system.service.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; + +/** + * 获取密钥 DTO + * + * @author rch + * @since 2020-08-25 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class GoogleAuthGenSecretDTO { + + /** 用户 */ + @NotBlank(message = "用户名不能为空") + private String userName; +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/GoogleAuthQrBarCodeUrlDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/GoogleAuthQrBarCodeUrlDTO.java new file mode 100644 index 0000000..049f341 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/GoogleAuthQrBarCodeUrlDTO.java @@ -0,0 +1,23 @@ +package me.zhengjie.modules.system.service.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; + +/** + * 获取密钥 DTO + * + * @author rch + * @since 2020-08-25 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class GoogleAuthQrBarCodeUrlDTO { + + /** 用户 */ + @NotBlank(message = "用户名不能为空") + private String userName; +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/JobDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/JobDto.java new file mode 100644 index 0000000..8836d55 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/JobDto.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import me.zhengjie.base.BaseDTO; + +import java.io.Serializable; + +/** +* @author Zheng Jie +* @date 2019-03-29 +*/ +@Getter +@Setter +@NoArgsConstructor +public class JobDto extends BaseDTO implements Serializable { + + private Long id; + + private Integer jobSort; + + private String name; + + private Boolean enabled; + + public JobDto(String name, Boolean enabled) { + this.name = name; + this.enabled = enabled; + } +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/JobQueryCriteria.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/JobQueryCriteria.java new file mode 100644 index 0000000..ee851dc --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/JobQueryCriteria.java @@ -0,0 +1,40 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; +import me.zhengjie.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** +* @author Zheng Jie +* @date 2019-6-4 14:49:34 +*/ +@Data +@NoArgsConstructor +public class JobQueryCriteria { + + @Query(type = Query.Type.INNER_LIKE) + private String name; + + @Query + private Boolean enabled; + + @Query(type = Query.Type.BETWEEN) + private List createTime; +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/JobSmallDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/JobSmallDto.java new file mode 100644 index 0000000..09cfa62 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/JobSmallDto.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; +import java.io.Serializable; + +/** +* @author Zheng Jie +* @date 2019-6-10 16:32:18 +*/ +@Data +@NoArgsConstructor +public class JobSmallDto implements Serializable { + + private Long id; + + private String name; +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/MenuDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/MenuDto.java new file mode 100644 index 0000000..d60dd29 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/MenuDto.java @@ -0,0 +1,91 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseDTO; +import java.io.Serializable; +import java.util.List; +import java.util.Objects; + +/** + * @author Zheng Jie + * @date 2018-12-17 + */ +@Getter +@Setter +public class MenuDto extends BaseDTO implements Serializable { + + private Long id; + + private List children; + + private Integer type; + + private String permission; + + private String title; + + private Integer menuSort; + + private String path; + + private String component; + + private Long pid; + + private Integer subCount; + + private Boolean iFrame; + + private Boolean cache; + + private Boolean hidden; + + private String componentName; + + private String icon; + + public Boolean getHasChildren() { + return subCount > 0; + } + + public Boolean getLeaf() { + return subCount <= 0; + } + + public String getLabel() { + return title; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MenuDto menuDto = (MenuDto) o; + return Objects.equals(id, menuDto.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/MenuQueryCriteria.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/MenuQueryCriteria.java new file mode 100644 index 0000000..bd43e8d --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/MenuQueryCriteria.java @@ -0,0 +1,41 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import lombok.Data; +import me.zhengjie.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** + * @author Zheng Jie + * 公共查询类 + */ +@Data +public class MenuQueryCriteria { + + @Query(blurry = "title,component,permission") + private String blurry; + + @Query(type = Query.Type.BETWEEN) + private List createTime; + + @Query(type = Query.Type.IS_NULL, propName = "pid") + private Boolean pidIsNull; + + @Query + private Long pid; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/RoleDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/RoleDto.java new file mode 100644 index 0000000..fc74d84 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/RoleDto.java @@ -0,0 +1,63 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseDTO; +import java.io.Serializable; +import java.util.Objects; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Getter +@Setter +public class RoleDto extends BaseDTO implements Serializable { + + private Long id; + + private Set menus; + + private Set depts; + + private String name; + + private String dataScope; + + private Integer level; + + private String description; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RoleDto roleDto = (RoleDto) o; + return Objects.equals(id, roleDto.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/RoleQueryCriteria.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/RoleQueryCriteria.java new file mode 100644 index 0000000..5454fc4 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/RoleQueryCriteria.java @@ -0,0 +1,36 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import lombok.Data; +import me.zhengjie.annotation.Query; + +import java.sql.Timestamp; +import java.util.List; + +/** + * @author Zheng Jie + * 公共查询类 + */ +@Data +public class RoleQueryCriteria { + + @Query(blurry = "name,description") + private String blurry; + + @Query(type = Query.Type.BETWEEN) + private List createTime; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/RoleSmallDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/RoleSmallDto.java new file mode 100644 index 0000000..99215e6 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/RoleSmallDto.java @@ -0,0 +1,35 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import lombok.Data; +import java.io.Serializable; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Data +public class RoleSmallDto implements Serializable { + + private Long id; + + private String name; + + private Integer level; + + private String dataScope; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/UpdateGoogleAuthDTO.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/UpdateGoogleAuthDTO.java new file mode 100644 index 0000000..befe410 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/UpdateGoogleAuthDTO.java @@ -0,0 +1,27 @@ +package me.zhengjie.modules.system.service.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +/** + * 修改Google认证器开关 DTO + * + * @author rch + * @since 2020-08-25 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UpdateGoogleAuthDTO { + + /** 用户 */ + @NotNull + @Min(value=0) + @Max(value=1) + private Integer isOpen; +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/UserDto.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/UserDto.java new file mode 100644 index 0000000..923e2d4 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/UserDto.java @@ -0,0 +1,67 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Getter; +import lombok.Setter; +import me.zhengjie.base.BaseDTO; +import java.io.Serializable; +import java.util.Date; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Getter +@Setter +public class UserDto extends BaseDTO implements Serializable { + + private Long id; + + private Set roles; + + private Set jobs; + + private DeptSmallDto dept; + + private Long deptId; + + private String username; + + private String nickName; + + private String email; + + private String phone; + + private String gender; + + private String avatarName; + + private String avatarPath; + + @JSONField(serialize = false) + private String password; + + private Boolean enabled; + + @JSONField(serialize = false) + private Boolean isAdmin = false; + + private Date pwdResetTime; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/UserQueryCriteria.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/UserQueryCriteria.java new file mode 100644 index 0000000..ad8e775 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/dto/UserQueryCriteria.java @@ -0,0 +1,49 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +import lombok.Data; +import me.zhengjie.annotation.Query; +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Data +public class UserQueryCriteria implements Serializable { + + @Query + private Long id; + + @Query(propName = "id", type = Query.Type.IN, joinName = "dept") + private Set deptIds = new HashSet<>(); + + @Query(blurry = "email,username,nickName") + private String blurry; + + @Query + private Boolean enabled; + + private Long deptId; + + @Query(type = Query.Type.BETWEEN) + private List createTime; +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/DataServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/DataServiceImpl.java new file mode 100644 index 0000000..33a8148 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/DataServiceImpl.java @@ -0,0 +1,91 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.impl; + +import lombok.RequiredArgsConstructor; +import me.zhengjie.modules.system.domain.Dept; +import me.zhengjie.modules.system.service.DataService; +import me.zhengjie.modules.system.service.DeptService; +import me.zhengjie.modules.system.service.RoleService; +import me.zhengjie.modules.system.service.dto.RoleSmallDto; +import me.zhengjie.modules.system.service.dto.UserDto; +import me.zhengjie.utils.enums.DataScopeEnum; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import java.util.*; + +/** + * @author Zheng Jie + * @website https://el-admin.vip + * @description 数据权限服务实现 + * @date 2020-05-07 + **/ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "data") +public class DataServiceImpl implements DataService { + + private final RoleService roleService; + private final DeptService deptService; + + /** + * 用户角色改变时需清理缓存 + * @param user / + * @return / + */ + @Override + @Cacheable(key = "'user:' + #p0.id") + public List getDeptIds(UserDto user) { + // 用于存储部门id + Set deptIds = new HashSet<>(); + // 查询用户角色 + List roleSet = roleService.findByUsersId(user.getId()); + // 获取对应的部门ID + for (RoleSmallDto role : roleSet) { + DataScopeEnum dataScopeEnum = DataScopeEnum.find(role.getDataScope()); + switch (Objects.requireNonNull(dataScopeEnum)) { + case THIS_LEVEL: + deptIds.add(user.getDept().getId()); + break; + case CUSTOMIZE: + deptIds.addAll(getCustomize(deptIds, role)); + break; + default: + return new ArrayList<>(deptIds); + } + } + return new ArrayList<>(deptIds); + } + + /** + * 获取自定义的数据权限 + * @param deptIds 部门ID + * @param role 角色 + * @return 数据权限ID + */ + public Set getCustomize(Set deptIds, RoleSmallDto role){ + Set depts = deptService.findByRoleId(role.getId()); + for (Dept dept : depts) { + deptIds.add(dept.getId()); + List deptChildren = deptService.findByPid(dept.getId()); + if (deptChildren != null && deptChildren.size() != 0) { + deptIds.addAll(deptService.getDeptChildren(deptChildren)); + } + } + return deptIds; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/DeptServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/DeptServiceImpl.java new file mode 100644 index 0000000..a02bd69 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/DeptServiceImpl.java @@ -0,0 +1,283 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.system.domain.Dept; +import me.zhengjie.modules.system.domain.User; +import me.zhengjie.modules.system.repository.RoleRepository; +import me.zhengjie.modules.system.repository.UserRepository; +import me.zhengjie.modules.system.service.dto.DeptDto; +import me.zhengjie.modules.system.service.dto.DeptQueryCriteria; +import me.zhengjie.utils.*; +import me.zhengjie.modules.system.repository.DeptRepository; +import me.zhengjie.modules.system.service.DeptService; +import me.zhengjie.modules.system.service.mapstruct.DeptMapper; +import me.zhengjie.utils.enums.DataScopeEnum; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.*; +import java.util.stream.Collectors; + +/** +* @author Zheng Jie +* @date 2019-03-25 +*/ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "dept") +public class DeptServiceImpl implements DeptService { + + private final DeptRepository deptRepository; + private final DeptMapper deptMapper; + private final UserRepository userRepository; + private final RedisUtils redisUtils; + private final RoleRepository roleRepository; + + @Override + public List queryAll(DeptQueryCriteria criteria, Boolean isQuery) throws Exception { + Sort sort = Sort.by(Sort.Direction.ASC, "deptSort"); + String dataScopeType = SecurityUtils.getDataScopeType(); + if (isQuery) { + if(dataScopeType.equals(DataScopeEnum.ALL.getValue())){ + criteria.setPidIsNull(true); + } + List fields = QueryHelp.getAllFields(criteria.getClass(), new ArrayList<>()); + List fieldNames = new ArrayList(){{ add("pidIsNull");add("enabled");}}; + for (Field field : fields) { + //设置对象的访问权限,保证对private的属性的访问 + field.setAccessible(true); + Object val = field.get(criteria); + if(fieldNames.contains(field.getName())){ + continue; + } + if (ObjectUtil.isNotNull(val)) { + criteria.setPidIsNull(null); + break; + } + } + } + List list = deptMapper.toDto(deptRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),sort)); + // 如果为空,就代表为自定义权限或者本级权限,就需要去重,不理解可以注释掉,看查询结果 + if(StringUtils.isBlank(dataScopeType)){ + return deduplication(list); + } + return list; + } + + @Override + @Cacheable(key = "'id:' + #p0") + public DeptDto findById(Long id) { + Dept dept = deptRepository.findById(id).orElseGet(Dept::new); + ValidationUtil.isNull(dept.getId(),"Dept","id",id); + return deptMapper.toDto(dept); + } + + @Override + public List findByPid(long pid) { + return deptRepository.findByPid(pid); + } + + @Override + public Set findByRoleId(Long id) { + return deptRepository.findByRoleId(id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Dept resources) { + deptRepository.save(resources); + // 计算子节点数目 + resources.setSubCount(0); + // 清理缓存 + updateSubCnt(resources.getPid()); + // 清理自定义角色权限的datascope缓存 + delCaches(resources.getPid()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(Dept resources) { + // 旧的部门 + Long oldPid = findById(resources.getId()).getPid(); + Long newPid = resources.getPid(); + if(resources.getPid() != null && resources.getId().equals(resources.getPid())) { + throw new BadRequestException("上级不能为自己"); + } + Dept dept = deptRepository.findById(resources.getId()).orElseGet(Dept::new); + ValidationUtil.isNull( dept.getId(),"Dept","id",resources.getId()); + resources.setId(dept.getId()); + deptRepository.save(resources); + // 更新父节点中子节点数目 + updateSubCnt(oldPid); + updateSubCnt(newPid); + // 清理缓存 + delCaches(resources.getId()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set deptDtos) { + for (DeptDto deptDto : deptDtos) { + // 清理缓存 + delCaches(deptDto.getId()); + deptRepository.deleteById(deptDto.getId()); + updateSubCnt(deptDto.getPid()); + } + } + + @Override + public void download(List deptDtos, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (DeptDto deptDTO : deptDtos) { + Map map = new LinkedHashMap<>(); + map.put("部门名称", deptDTO.getName()); + map.put("部门状态", deptDTO.getEnabled() ? "启用" : "停用"); + map.put("创建日期", deptDTO.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + @Override + public Set getDeleteDepts(List menuList, Set deptDtos) { + for (Dept dept : menuList) { + deptDtos.add(deptMapper.toDto(dept)); + List depts = deptRepository.findByPid(dept.getId()); + if(depts!=null && depts.size()!=0){ + getDeleteDepts(depts, deptDtos); + } + } + return deptDtos; + } + + @Override + public List getDeptChildren(List deptList) { + List list = new ArrayList<>(); + deptList.forEach(dept -> { + if (dept!=null && dept.getEnabled()) { + List depts = deptRepository.findByPid(dept.getId()); + if (depts.size() != 0) { + list.addAll(getDeptChildren(depts)); + } + list.add(dept.getId()); + } + } + ); + return list; + } + + @Override + public List getSuperior(DeptDto deptDto, List depts) { + if(deptDto.getPid() == null){ + depts.addAll(deptRepository.findByPidIsNull()); + return deptMapper.toDto(depts); + } + depts.addAll(deptRepository.findByPid(deptDto.getPid())); + return getSuperior(findById(deptDto.getPid()), depts); + } + + @Override + public Object buildTree(List deptDtos) { + Set trees = new LinkedHashSet<>(); + Set depts= new LinkedHashSet<>(); + List deptNames = deptDtos.stream().map(DeptDto::getName).collect(Collectors.toList()); + boolean isChild; + for (DeptDto deptDTO : deptDtos) { + isChild = false; + if (deptDTO.getPid() == null) { + trees.add(deptDTO); + } + for (DeptDto it : deptDtos) { + if (it.getPid() != null && deptDTO.getId().equals(it.getPid())) { + isChild = true; + if (deptDTO.getChildren() == null) { + deptDTO.setChildren(new ArrayList<>()); + } + deptDTO.getChildren().add(it); + } + } + if(isChild) { + depts.add(deptDTO); + } else if(deptDTO.getPid() != null && !deptNames.contains(findById(deptDTO.getPid()).getName())) { + depts.add(deptDTO); + } + } + + if (CollectionUtil.isEmpty(trees)) { + trees = depts; + } + Map map = new HashMap<>(2); + map.put("totalElements",deptDtos.size()); + map.put("content",CollectionUtil.isEmpty(trees)? deptDtos :trees); + return map; + } + + @Override + public void verification(Set deptDtos) { + Set deptIds = deptDtos.stream().map(DeptDto::getId).collect(Collectors.toSet()); + if(userRepository.countByDepts(deptIds) > 0){ + throw new BadRequestException("所选部门存在用户关联,请解除后再试!"); + } + if(roleRepository.countByDepts(deptIds) > 0){ + throw new BadRequestException("所选部门存在角色关联,请解除后再试!"); + } + } + + private void updateSubCnt(Long deptId){ + if(deptId != null){ + int count = deptRepository.countByPid(deptId); + deptRepository.updateSubCntById(count, deptId); + } + } + + private List deduplication(List list) { + List deptDtos = new ArrayList<>(); + for (DeptDto deptDto : list) { + boolean flag = true; + for (DeptDto dto : list) { + if (dto.getId().equals(deptDto.getPid())) { + flag = false; + break; + } + } + if (flag){ + deptDtos.add(deptDto); + } + } + return deptDtos; + } + + /** + * 清理缓存 + * @param id / + */ + public void delCaches(Long id){ + List users = userRepository.findByRoleDeptId(id); + // 删除数据权限 + redisUtils.delByKeys(CacheKey.DATA_USER, users.stream().map(User::getId).collect(Collectors.toSet())); + redisUtils.del(CacheKey.DEPT_ID + id); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/DictDetailServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/DictDetailServiceImpl.java new file mode 100644 index 0000000..3f5fc74 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/DictDetailServiceImpl.java @@ -0,0 +1,95 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.impl; + +import lombok.RequiredArgsConstructor; +import me.zhengjie.modules.system.domain.Dict; +import me.zhengjie.modules.system.domain.DictDetail; +import me.zhengjie.modules.system.repository.DictRepository; +import me.zhengjie.modules.system.service.dto.DictDetailQueryCriteria; +import me.zhengjie.utils.*; +import me.zhengjie.modules.system.repository.DictDetailRepository; +import me.zhengjie.modules.system.service.DictDetailService; +import me.zhengjie.modules.system.service.dto.DictDetailDto; +import me.zhengjie.modules.system.service.mapstruct.DictDetailMapper; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.util.List; +import java.util.Map; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "dict") +public class DictDetailServiceImpl implements DictDetailService { + + private final DictRepository dictRepository; + private final DictDetailRepository dictDetailRepository; + private final DictDetailMapper dictDetailMapper; + private final RedisUtils redisUtils; + + @Override + public Map queryAll(DictDetailQueryCriteria criteria, Pageable pageable) { + Page page = dictDetailRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); + return PageUtil.toPage(page.map(dictDetailMapper::toDto)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(DictDetail resources) { + dictDetailRepository.save(resources); + // 清理缓存 + delCaches(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(DictDetail resources) { + DictDetail dictDetail = dictDetailRepository.findById(resources.getId()).orElseGet(DictDetail::new); + ValidationUtil.isNull( dictDetail.getId(),"DictDetail","id",resources.getId()); + resources.setId(dictDetail.getId()); + dictDetailRepository.save(resources); + // 清理缓存 + delCaches(resources); + } + + @Override + @Cacheable(key = "'name:' + #p0") + public List getDictByName(String name) { + return dictDetailMapper.toDto(dictDetailRepository.findByDictName(name)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Long id) { + DictDetail dictDetail = dictDetailRepository.findById(id).orElseGet(DictDetail::new); + // 清理缓存 + delCaches(dictDetail); + dictDetailRepository.deleteById(id); + } + + public void delCaches(DictDetail dictDetail){ + Dict dict = dictRepository.findById(dictDetail.getDict().getId()).orElseGet(Dict::new); + redisUtils.del(CacheKey.DICT_NAME + dict.getName()); + } +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/DictServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/DictServiceImpl.java new file mode 100644 index 0000000..3a2bcd9 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/DictServiceImpl.java @@ -0,0 +1,121 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import lombok.RequiredArgsConstructor; +import me.zhengjie.modules.system.domain.Dict; +import me.zhengjie.modules.system.service.dto.DictDetailDto; +import me.zhengjie.modules.system.service.dto.DictQueryCriteria; +import me.zhengjie.utils.*; +import me.zhengjie.modules.system.repository.DictRepository; +import me.zhengjie.modules.system.service.DictService; +import me.zhengjie.modules.system.service.dto.DictDto; +import me.zhengjie.modules.system.service.mapstruct.DictMapper; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "dict") +public class DictServiceImpl implements DictService { + + private final DictRepository dictRepository; + private final DictMapper dictMapper; + private final RedisUtils redisUtils; + + @Override + public Map queryAll(DictQueryCriteria dict, Pageable pageable){ + Page page = dictRepository.findAll((root, query, cb) -> QueryHelp.getPredicate(root, dict, cb), pageable); + return PageUtil.toPage(page.map(dictMapper::toDto)); + } + + @Override + public List queryAll(DictQueryCriteria dict) { + List list = dictRepository.findAll((root, query, cb) -> QueryHelp.getPredicate(root, dict, cb)); + return dictMapper.toDto(list); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Dict resources) { + dictRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(Dict resources) { + // 清理缓存 + delCaches(resources); + Dict dict = dictRepository.findById(resources.getId()).orElseGet(Dict::new); + ValidationUtil.isNull( dict.getId(),"Dict","id",resources.getId()); + dict.setName(resources.getName()); + dict.setDescription(resources.getDescription()); + dictRepository.save(dict); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + // 清理缓存 + List dicts = dictRepository.findByIdIn(ids); + for (Dict dict : dicts) { + delCaches(dict); + } + dictRepository.deleteByIdIn(ids); + } + + @Override + public void download(List dictDtos, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (DictDto dictDTO : dictDtos) { + if(CollectionUtil.isNotEmpty(dictDTO.getDictDetails())){ + for (DictDetailDto dictDetail : dictDTO.getDictDetails()) { + Map map = new LinkedHashMap<>(); + map.put("字典名称", dictDTO.getName()); + map.put("字典描述", dictDTO.getDescription()); + map.put("字典标签", dictDetail.getLabel()); + map.put("字典值", dictDetail.getValue()); + map.put("创建日期", dictDetail.getCreateTime()); + list.add(map); + } + } else { + Map map = new LinkedHashMap<>(); + map.put("字典名称", dictDTO.getName()); + map.put("字典描述", dictDTO.getDescription()); + map.put("字典标签", null); + map.put("字典值", null); + map.put("创建日期", dictDTO.getCreateTime()); + list.add(map); + } + } + FileUtil.downloadExcel(list, response); + } + + public void delCaches(Dict dict){ + redisUtils.del(CacheKey.DICT_NAME + dict.getName()); + } +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/JobServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/JobServiceImpl.java new file mode 100644 index 0000000..5c76dfc --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/JobServiceImpl.java @@ -0,0 +1,132 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.impl; + +import lombok.RequiredArgsConstructor; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.exception.EntityExistException; +import me.zhengjie.modules.system.domain.Job; +import me.zhengjie.modules.system.repository.UserRepository; +import me.zhengjie.modules.system.service.dto.JobQueryCriteria; +import me.zhengjie.utils.*; +import me.zhengjie.modules.system.repository.JobRepository; +import me.zhengjie.modules.system.service.JobService; +import me.zhengjie.modules.system.service.dto.JobDto; +import me.zhengjie.modules.system.service.mapstruct.JobMapper; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** +* @author Zheng Jie +* @date 2019-03-29 +*/ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "job") +public class JobServiceImpl implements JobService { + + private final JobRepository jobRepository; + private final JobMapper jobMapper; + private final RedisUtils redisUtils; + private final UserRepository userRepository; + + @Override + public Map queryAll(JobQueryCriteria criteria, Pageable pageable) { + Page page = jobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); + return PageUtil.toPage(page.map(jobMapper::toDto).getContent(),page.getTotalElements()); + } + + @Override + public List queryAll(JobQueryCriteria criteria) { + List list = jobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)); + return jobMapper.toDto(list); + } + + @Override + @Cacheable(key = "'id:' + #p0") + public JobDto findById(Long id) { + Job job = jobRepository.findById(id).orElseGet(Job::new); + ValidationUtil.isNull(job.getId(),"Job","id",id); + return jobMapper.toDto(job); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Job resources) { + Job job = jobRepository.findByName(resources.getName()); + if(job != null){ + throw new EntityExistException(Job.class,"name",resources.getName()); + } + jobRepository.save(resources); + } + + @Override + @CacheEvict(key = "'id:' + #p0.id") + @Transactional(rollbackFor = Exception.class) + public void update(Job resources) { + Job job = jobRepository.findById(resources.getId()).orElseGet(Job::new); + Job old = jobRepository.findByName(resources.getName()); + if(old != null && !old.getId().equals(resources.getId())){ + throw new EntityExistException(Job.class,"name",resources.getName()); + } + ValidationUtil.isNull( job.getId(),"Job","id",resources.getId()); + resources.setId(job.getId()); + jobRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + jobRepository.deleteAllByIdIn(ids); + jobRepository.deleteAll(); + // 删除缓存 + redisUtils.delByKeys(CacheKey.JOB_ID, ids); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete() { + jobRepository.deleteAll(); + } + + @Override + public void download(List jobDtos, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (JobDto jobDTO : jobDtos) { + Map map = new LinkedHashMap<>(); + map.put("岗位名称", jobDTO.getName()); + map.put("岗位状态", jobDTO.getEnabled() ? "启用" : "停用"); + map.put("创建日期", jobDTO.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + @Override + public void verification(Set ids) { + if(userRepository.countByJobs(ids) > 0){ + throw new BadRequestException("所选的岗位中存在用户关联,请解除关联再试!"); + } + } +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/MenuServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/MenuServiceImpl.java new file mode 100644 index 0000000..0e54fc9 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/MenuServiceImpl.java @@ -0,0 +1,355 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import me.zhengjie.modules.system.domain.Menu; +import me.zhengjie.modules.system.domain.Role; +import me.zhengjie.modules.system.domain.User; +import me.zhengjie.modules.system.domain.vo.MenuMetaVo; +import me.zhengjie.modules.system.domain.vo.MenuVo; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.exception.EntityExistException; +import me.zhengjie.modules.system.repository.MenuRepository; +import me.zhengjie.modules.system.repository.UserRepository; +import me.zhengjie.modules.system.service.MenuService; +import me.zhengjie.modules.system.service.RoleService; +import me.zhengjie.modules.system.service.dto.MenuDto; +import me.zhengjie.modules.system.service.dto.MenuQueryCriteria; +import me.zhengjie.modules.system.service.dto.RoleSmallDto; +import me.zhengjie.modules.system.service.mapstruct.MenuMapper; +import me.zhengjie.utils.*; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Zheng Jie + */ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "menu") +public class MenuServiceImpl implements MenuService { + + private final MenuRepository menuRepository; + private final UserRepository userRepository; + private final MenuMapper menuMapper; + private final RoleService roleService; + private final RedisUtils redisUtils; + + @Override + public List queryAll(MenuQueryCriteria criteria, Boolean isQuery) throws Exception { + Sort sort = Sort.by(Sort.Direction.ASC, "menuSort"); + if(isQuery){ + criteria.setPidIsNull(true); + List fields = QueryHelp.getAllFields(criteria.getClass(), new ArrayList<>()); + for (Field field : fields) { + //设置对象的访问权限,保证对private的属性的访问 + field.setAccessible(true); + Object val = field.get(criteria); + if("pidIsNull".equals(field.getName())){ + continue; + } + if (ObjectUtil.isNotNull(val)) { + criteria.setPidIsNull(null); + break; + } + } + } + return menuMapper.toDto(menuRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),sort)); + } + + @Override + @Cacheable(key = "'id:' + #p0") + public MenuDto findById(long id) { + Menu menu = menuRepository.findById(id).orElseGet(Menu::new); + ValidationUtil.isNull(menu.getId(),"Menu","id",id); + return menuMapper.toDto(menu); + } + + /** + * 用户角色改变时需清理缓存 + * @param currentUserId / + * @return / + */ + @Override + @Cacheable(key = "'user:' + #p0") + public List findByUser(Long currentUserId) { + List roles = roleService.findByUsersId(currentUserId); + Set roleIds = roles.stream().map(RoleSmallDto::getId).collect(Collectors.toSet()); + LinkedHashSet menus = menuRepository.findByRoleIdsAndTypeNot(roleIds, 2); + return menus.stream().map(menuMapper::toDto).collect(Collectors.toList()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Menu resources) { + if(menuRepository.findByTitle(resources.getTitle()) != null){ + throw new EntityExistException(Menu.class,"title",resources.getTitle()); + } + if(StringUtils.isNotBlank(resources.getComponentName())){ + if(menuRepository.findByComponentName(resources.getComponentName()) != null){ + throw new EntityExistException(Menu.class,"componentName",resources.getComponentName()); + } + } + if(resources.getPid().equals(0L)){ + resources.setPid(null); + } + if(resources.getIFrame()){ + String http = "http://", https = "https://"; + if (!(resources.getPath().toLowerCase().startsWith(http)||resources.getPath().toLowerCase().startsWith(https))) { + throw new BadRequestException("外链必须以http://或者https://开头"); + } + } + menuRepository.save(resources); + // 计算子节点数目 + resources.setSubCount(0); + // 更新父节点菜单数目 + updateSubCnt(resources.getPid()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(Menu resources) { + if(resources.getId().equals(resources.getPid())) { + throw new BadRequestException("上级不能为自己"); + } + Menu menu = menuRepository.findById(resources.getId()).orElseGet(Menu::new); + ValidationUtil.isNull(menu.getId(),"Permission","id",resources.getId()); + + if(resources.getIFrame()){ + String http = "http://", https = "https://"; + if (!(resources.getPath().toLowerCase().startsWith(http)||resources.getPath().toLowerCase().startsWith(https))) { + throw new BadRequestException("外链必须以http://或者https://开头"); + } + } + Menu menu1 = menuRepository.findByTitle(resources.getTitle()); + + if(menu1 != null && !menu1.getId().equals(menu.getId())){ + throw new EntityExistException(Menu.class,"title",resources.getTitle()); + } + + if(resources.getPid().equals(0L)){ + resources.setPid(null); + } + + // 记录的父节点ID + Long oldPid = menu.getPid(); + Long newPid = resources.getPid(); + + if(StringUtils.isNotBlank(resources.getComponentName())){ + menu1 = menuRepository.findByComponentName(resources.getComponentName()); + if(menu1 != null && !menu1.getId().equals(menu.getId())){ + throw new EntityExistException(Menu.class,"componentName",resources.getComponentName()); + } + } + menu.setTitle(resources.getTitle()); + menu.setComponent(resources.getComponent()); + menu.setPath(resources.getPath()); + menu.setIcon(resources.getIcon()); + menu.setIFrame(resources.getIFrame()); + menu.setPid(resources.getPid()); + menu.setMenuSort(resources.getMenuSort()); + menu.setCache(resources.getCache()); + menu.setHidden(resources.getHidden()); + menu.setComponentName(resources.getComponentName()); + menu.setPermission(resources.getPermission()); + menu.setType(resources.getType()); + menuRepository.save(menu); + // 计算父级菜单节点数目 + updateSubCnt(oldPid); + updateSubCnt(newPid); + // 清理缓存 + delCaches(resources.getId()); + } + + @Override + public Set getChildMenus(List menuList, Set menuSet) { + for (Menu menu : menuList) { + menuSet.add(menu); + List menus = menuRepository.findByPid(menu.getId()); + if(menus!=null && menus.size()!=0){ + getChildMenus(menus, menuSet); + } + } + return menuSet; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set menuSet) { + for (Menu menu : menuSet) { + // 清理缓存 + delCaches(menu.getId()); + roleService.untiedMenu(menu.getId()); + menuRepository.deleteById(menu.getId()); + updateSubCnt(menu.getPid()); + } + } + + @Override + public List getMenus(Long pid) { + List menus; + if(pid != null && !pid.equals(0L)){ + menus = menuRepository.findByPid(pid); + } else { + menus = menuRepository.findByPidIsNull(); + } + return menuMapper.toDto(menus); + } + + @Override + public List getSuperior(MenuDto menuDto, List menus) { + if(menuDto.getPid() == null){ + menus.addAll(menuRepository.findByPidIsNull()); + return menuMapper.toDto(menus); + } + menus.addAll(menuRepository.findByPid(menuDto.getPid())); + return getSuperior(findById(menuDto.getPid()), menus); + } + + @Override + public List buildTree(List menuDtos) { + List trees = new ArrayList<>(); + Set ids = new HashSet<>(); + for (MenuDto menuDTO : menuDtos) { + if (menuDTO.getPid() == null) { + trees.add(menuDTO); + } + for (MenuDto it : menuDtos) { + if (menuDTO.getId().equals(it.getPid())) { + if (menuDTO.getChildren() == null) { + menuDTO.setChildren(new ArrayList<>()); + } + menuDTO.getChildren().add(it); + ids.add(it.getId()); + } + } + } + if(trees.size() == 0){ + trees = menuDtos.stream().filter(s -> !ids.contains(s.getId())).collect(Collectors.toList()); + } + return trees; + } + + @Override + public List buildMenus(List menuDtos) { + List list = new LinkedList<>(); + menuDtos.forEach(menuDTO -> { + if (menuDTO!=null){ + List menuDtoList = menuDTO.getChildren(); + MenuVo menuVo = new MenuVo(); + menuVo.setName(ObjectUtil.isNotEmpty(menuDTO.getComponentName()) ? menuDTO.getComponentName() : menuDTO.getTitle()); + // 一级目录需要加斜杠,不然会报警告 + menuVo.setPath(menuDTO.getPid() == null ? "/" + menuDTO.getPath() :menuDTO.getPath()); + menuVo.setHidden(menuDTO.getHidden()); + // 如果不是外链 + if(!menuDTO.getIFrame()){ + if(menuDTO.getPid() == null){ + menuVo.setComponent(StringUtils.isEmpty(menuDTO.getComponent())?"Layout":menuDTO.getComponent()); + // 如果不是一级菜单,并且菜单类型为目录,则代表是多级菜单 + }else if(menuDTO.getType() == 0){ + menuVo.setComponent(StringUtils.isEmpty(menuDTO.getComponent())?"ParentView":menuDTO.getComponent()); + }else if(StringUtils.isNoneBlank(menuDTO.getComponent())){ + menuVo.setComponent(menuDTO.getComponent()); + } + } + menuVo.setMeta(new MenuMetaVo(menuDTO.getTitle(),menuDTO.getIcon(),!menuDTO.getCache())); + if(CollectionUtil.isNotEmpty(menuDtoList)){ + menuVo.setAlwaysShow(true); + menuVo.setRedirect("noredirect"); + menuVo.setChildren(buildMenus(menuDtoList)); + // 处理是一级菜单并且没有子菜单的情况 + } else if(menuDTO.getPid() == null){ + MenuVo menuVo1 = new MenuVo(); + menuVo1.setMeta(menuVo.getMeta()); + // 非外链 + if(!menuDTO.getIFrame()){ + menuVo1.setPath("index"); + menuVo1.setName(menuVo.getName()); + menuVo1.setComponent(menuVo.getComponent()); + } else { + menuVo1.setPath(menuDTO.getPath()); + } + menuVo.setName(null); + menuVo.setMeta(null); + menuVo.setComponent("Layout"); + List list1 = new ArrayList<>(); + list1.add(menuVo1); + menuVo.setChildren(list1); + } + list.add(menuVo); + } + } + ); + return list; + } + + @Override + public Menu findOne(Long id) { + Menu menu = menuRepository.findById(id).orElseGet(Menu::new); + ValidationUtil.isNull(menu.getId(),"Menu","id",id); + return menu; + } + + @Override + public void download(List menuDtos, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (MenuDto menuDTO : menuDtos) { + Map map = new LinkedHashMap<>(); + map.put("菜单标题", menuDTO.getTitle()); + map.put("菜单类型", menuDTO.getType() == null ? "目录" : menuDTO.getType() == 1 ? "菜单" : "按钮"); + map.put("权限标识", menuDTO.getPermission()); + map.put("外链菜单", menuDTO.getIFrame() ? "是" : "否"); + map.put("菜单可见", menuDTO.getHidden() ? "否" : "是"); + map.put("是否缓存", menuDTO.getCache() ? "是" : "否"); + map.put("创建日期", menuDTO.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + private void updateSubCnt(Long menuId){ + if(menuId != null){ + int count = menuRepository.countByPid(menuId); + menuRepository.updateSubCntById(count, menuId); + } + } + + /** + * 清理缓存 + * @param id 菜单ID + */ + public void delCaches(Long id){ + List users = userRepository.findByMenuId(id); + redisUtils.del(CacheKey.MENU_ID + id); + redisUtils.delByKeys(CacheKey.MENU_USER, users.stream().map(User::getId).collect(Collectors.toSet())); + // 清除 Role 缓存 + List roles = roleService.findInMenuId(new ArrayList(){{ + add(id); + }}); + redisUtils.delByKeys(CacheKey.ROLE_ID, roles.stream().map(Role::getId).collect(Collectors.toSet())); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/MonitorServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/MonitorServiceImpl.java new file mode 100644 index 0000000..7ff2e91 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/MonitorServiceImpl.java @@ -0,0 +1,187 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.impl; + +import cn.hutool.core.date.BetweenFormater; +import cn.hutool.core.date.DateUtil; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.system.service.MonitorService; +import me.zhengjie.utils.ElAdminConstant; +import me.zhengjie.utils.FileUtil; +import me.zhengjie.utils.StringUtils; +import org.springframework.stereotype.Service; +import oshi.SystemInfo; +import oshi.hardware.*; +import oshi.software.os.FileSystem; +import oshi.software.os.OSFileStore; +import oshi.software.os.OperatingSystem; +import oshi.util.FormatUtil; +import oshi.util.Util; +import java.lang.management.ManagementFactory; +import java.text.DecimalFormat; +import java.util.*; + +/** +* @author Zheng Jie +* @date 2020-05-02 +*/ +@Service +public class MonitorServiceImpl implements MonitorService { + + private final DecimalFormat df = new DecimalFormat("0.00"); + + @Override + public Map getServers(){ + Map resultMap = new LinkedHashMap<>(8); + try { + SystemInfo si = new SystemInfo(); + OperatingSystem os = si.getOperatingSystem(); + HardwareAbstractionLayer hal = si.getHardware(); + // 系统信息 + resultMap.put("sys", getSystemInfo(os)); + // cpu 信息 + resultMap.put("cpu", getCpuInfo(hal.getProcessor())); + // 内存信息 + resultMap.put("memory", getMemoryInfo(hal.getMemory())); + // 交换区信息 + resultMap.put("swap", getSwapInfo(hal.getMemory())); + // 磁盘 + resultMap.put("disk", getDiskInfo(os)); + resultMap.put("time", DateUtil.format(new Date(), "HH:mm:ss")); + } catch (Exception e) { + e.printStackTrace(); + } + return resultMap; + } + + /** + * 获取磁盘信息 + * @return / + */ + private Map getDiskInfo(OperatingSystem os) { + Map diskInfo = new LinkedHashMap<>(); + FileSystem fileSystem = os.getFileSystem(); + List fsArray = fileSystem.getFileStores(); + String osName = System.getProperty("os.name"); + long available = 0, total = 0; + for (OSFileStore fs : fsArray){ + // windows 需要将所有磁盘分区累加,linux 和 mac 直接累加会出现磁盘重复的问题,待修复 + if(osName.toLowerCase().startsWith(ElAdminConstant.WIN)) { + available += fs.getUsableSpace(); + total += fs.getTotalSpace(); + } else { + available = fs.getUsableSpace(); + total = fs.getTotalSpace(); + break; + } + } + long used = total - available; + diskInfo.put("total", total > 0 ? FileUtil.getSize(total) : "?"); + diskInfo.put("available", FileUtil.getSize(available)); + diskInfo.put("used", FileUtil.getSize(used)); + if(total != 0){ + diskInfo.put("usageRate", df.format(used/(double)total * 100)); + } else { + diskInfo.put("usageRate", 0); + } + return diskInfo; + } + + /** + * 获取交换区信息 + * @param memory / + * @return / + */ + private Map getSwapInfo(GlobalMemory memory) { + Map swapInfo = new LinkedHashMap<>(); + VirtualMemory virtualMemory = memory.getVirtualMemory(); + long total = virtualMemory.getSwapTotal(); + long used = virtualMemory.getSwapUsed(); + swapInfo.put("total", FormatUtil.formatBytes(total)); + swapInfo.put("used", FormatUtil.formatBytes(used)); + swapInfo.put("available", FormatUtil.formatBytes(total - used)); + if(used == 0){ + swapInfo.put("usageRate", 0); + } else { + swapInfo.put("usageRate", df.format(used/(double)total * 100)); + } + return swapInfo; + } + + /** + * 获取内存信息 + * @param memory / + * @return / + */ + private Map getMemoryInfo(GlobalMemory memory) { + Map memoryInfo = new LinkedHashMap<>(); + memoryInfo.put("total", FormatUtil.formatBytes(memory.getTotal())); + memoryInfo.put("available", FormatUtil.formatBytes(memory.getAvailable())); + memoryInfo.put("used", FormatUtil.formatBytes(memory.getTotal() - memory.getAvailable())); + memoryInfo.put("usageRate", df.format((memory.getTotal() - memory.getAvailable())/(double)memory.getTotal() * 100)); + return memoryInfo; + } + + /** + * 获取Cpu相关信息 + * @param processor / + * @return / + */ + private Map getCpuInfo(CentralProcessor processor) { + Map cpuInfo = new LinkedHashMap<>(); + cpuInfo.put("name", processor.getProcessorIdentifier().getName()); + cpuInfo.put("package", processor.getPhysicalPackageCount() + "个物理CPU"); + cpuInfo.put("core", processor.getPhysicalProcessorCount() + "个物理核心"); + cpuInfo.put("coreNumber", processor.getPhysicalProcessorCount()); + cpuInfo.put("logic", processor.getLogicalProcessorCount() + "个逻辑CPU"); + // CPU信息 + long[] prevTicks = processor.getSystemCpuLoadTicks(); + // 等待1秒... + Util.sleep(1000); + long[] ticks = processor.getSystemCpuLoadTicks(); + long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()]; + long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()]; + long sys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()]; + long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()]; + long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()]; + long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()]; + long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()]; + long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()]; + long totalCpu = user + nice + sys + idle + iowait + irq + softirq + steal; + cpuInfo.put("used", df.format(100d * user / totalCpu + 100d * sys / totalCpu)); + cpuInfo.put("idle", df.format(100d * idle / totalCpu)); + return cpuInfo; + } + + /** + * 获取系统相关信息,系统、运行天数、系统IP + * @param os / + * @return / + */ + private Map getSystemInfo(OperatingSystem os){ + Map systemInfo = new LinkedHashMap<>(); + // jvm 运行时间 + long time = ManagementFactory.getRuntimeMXBean().getStartTime(); + Date date = new Date(time); + // 计算项目运行时间 + String formatBetween = DateUtil.formatBetween(date, new Date(),BetweenFormater.Level.HOUR); + // 系统信息 + systemInfo.put("os", os.toString()); + systemInfo.put("day", formatBetween); + systemInfo.put("ip", StringUtils.getLocalIp()); + return systemInfo; + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/RoleServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/RoleServiceImpl.java new file mode 100644 index 0000000..e8b4143 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/RoleServiceImpl.java @@ -0,0 +1,226 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import lombok.RequiredArgsConstructor; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.security.service.UserCacheClean; +import me.zhengjie.modules.system.domain.Menu; +import me.zhengjie.modules.system.domain.Role; +import me.zhengjie.exception.EntityExistException; +import me.zhengjie.modules.system.domain.User; +import me.zhengjie.modules.system.repository.RoleRepository; +import me.zhengjie.modules.system.repository.UserRepository; +import me.zhengjie.modules.system.service.RoleService; +import me.zhengjie.modules.system.service.dto.RoleDto; +import me.zhengjie.modules.system.service.dto.RoleQueryCriteria; +import me.zhengjie.modules.system.service.dto.RoleSmallDto; +import me.zhengjie.modules.system.service.dto.UserDto; +import me.zhengjie.modules.system.service.mapstruct.RoleMapper; +import me.zhengjie.modules.system.service.mapstruct.RoleSmallMapper; +import me.zhengjie.utils.*; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Zheng Jie + * @date 2018-12-03 + */ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "role") +public class RoleServiceImpl implements RoleService { + + private final RoleRepository roleRepository; + private final RoleMapper roleMapper; + private final RoleSmallMapper roleSmallMapper; + private final RedisUtils redisUtils; + private final UserRepository userRepository; + private final UserCacheClean userCacheClean; + + @Override + public List queryAll() { + Sort sort = Sort.by(Sort.Direction.ASC, "level"); + return roleMapper.toDto(roleRepository.findAll(sort)); + } + + @Override + public List queryAll(RoleQueryCriteria criteria) { + return roleMapper.toDto(roleRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder))); + } + + @Override + public Object queryAll(RoleQueryCriteria criteria, Pageable pageable) { + Page page = roleRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable); + return PageUtil.toPage(page.map(roleMapper::toDto)); + } + + @Override + @Cacheable(key = "'id:' + #p0") + @Transactional(rollbackFor = Exception.class) + public RoleDto findById(long id) { + Role role = roleRepository.findById(id).orElseGet(Role::new); + ValidationUtil.isNull(role.getId(), "Role", "id", id); + return roleMapper.toDto(role); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Role resources) { + if (roleRepository.findByName(resources.getName()) != null) { + throw new EntityExistException(Role.class, "username", resources.getName()); + } + roleRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(Role resources) { + Role role = roleRepository.findById(resources.getId()).orElseGet(Role::new); + ValidationUtil.isNull(role.getId(), "Role", "id", resources.getId()); + + Role role1 = roleRepository.findByName(resources.getName()); + + if (role1 != null && !role1.getId().equals(role.getId())) { + throw new EntityExistException(Role.class, "username", resources.getName()); + } + role.setName(resources.getName()); + role.setDescription(resources.getDescription()); + role.setDataScope(resources.getDataScope()); + role.setDepts(resources.getDepts()); + role.setLevel(resources.getLevel()); + roleRepository.save(role); + // 更新相关缓存 + delCaches(role.getId(), null); + } + + @Override + public void updateMenu(Role resources, RoleDto roleDTO) { + Role role = roleMapper.toEntity(roleDTO); + List users = userRepository.findByRoleId(role.getId()); + // 更新菜单 + role.setMenus(resources.getMenus()); + delCaches(resources.getId(), users); + roleRepository.save(role); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void untiedMenu(Long menuId) { + // 更新菜单 + roleRepository.untiedMenu(menuId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + for (Long id : ids) { + // 更新相关缓存 + delCaches(id, null); + } + roleRepository.deleteAllByIdIn(ids); + } + + @Override + public List findByUsersId(Long id) { + return roleSmallMapper.toDto(new ArrayList<>(roleRepository.findByUserId(id))); + } + + @Override + public Integer findByRoles(Set roles) { + if (roles.size() == 0) { + return Integer.MAX_VALUE; + } + Set roleDtos = new HashSet<>(); + for (Role role : roles) { + roleDtos.add(findById(role.getId())); + } + return Collections.min(roleDtos.stream().map(RoleDto::getLevel).collect(Collectors.toList())); + } + + @Override + @Cacheable(key = "'auth:' + #p0.id") + public List mapToGrantedAuthorities(UserDto user) { + Set permissions = new HashSet<>(); + // 如果是管理员直接返回 + if (user.getIsAdmin()) { + permissions.add("admin"); + return permissions.stream().map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + } + Set roles = roleRepository.findByUserId(user.getId()); + permissions = roles.stream().flatMap(role -> role.getMenus().stream()) + .filter(menu -> StringUtils.isNotBlank(menu.getPermission())) + .map(Menu::getPermission).collect(Collectors.toSet()); + return permissions.stream().map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + } + + @Override + public void download(List roles, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (RoleDto role : roles) { + Map map = new LinkedHashMap<>(); + map.put("角色名称", role.getName()); + map.put("角色级别", role.getLevel()); + map.put("描述", role.getDescription()); + map.put("创建日期", role.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + @Override + public void verification(Set ids) { + if (userRepository.countByRoles(ids) > 0) { + throw new BadRequestException("所选角色存在用户关联,请解除关联再试!"); + } + } + + @Override + public List findInMenuId(List menuIds) { + return roleRepository.findInMenuId(menuIds); + } + + /** + * 清理缓存 + * @param id / + */ + public void delCaches(Long id, List users) { + users = CollectionUtil.isEmpty(users) ? userRepository.findByRoleId(id) : users; + if (CollectionUtil.isNotEmpty(users)) { + users.forEach(item -> userCacheClean.cleanUserCache(item.getUsername())); + Set userIds = users.stream().map(User::getId).collect(Collectors.toSet()); + redisUtils.delByKeys(CacheKey.DATA_USER, userIds); + redisUtils.delByKeys(CacheKey.MENU_USER, userIds); + redisUtils.delByKeys(CacheKey.ROLE_AUTH, userIds); + } + redisUtils.del(CacheKey.ROLE_ID + id); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/UserServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..3a56692 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/UserServiceImpl.java @@ -0,0 +1,282 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import lombok.RequiredArgsConstructor; +import me.zhengjie.config.FileProperties; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.security.service.OnlineUserService; +import me.zhengjie.modules.security.service.UserCacheClean; +import me.zhengjie.modules.system.domain.User; +import me.zhengjie.exception.EntityExistException; +import me.zhengjie.exception.EntityNotFoundException; +import me.zhengjie.modules.system.repository.UserRepository; +import me.zhengjie.modules.system.service.UserService; +import me.zhengjie.modules.system.service.dto.JobSmallDto; +import me.zhengjie.modules.system.service.dto.RoleSmallDto; +import me.zhengjie.modules.system.service.dto.UserDto; +import me.zhengjie.modules.system.service.dto.UserQueryCriteria; +import me.zhengjie.modules.system.service.mapstruct.UserMapper; +import me.zhengjie.utils.*; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotBlank; +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "user") +public class UserServiceImpl implements UserService { + + private final UserRepository userRepository; + private final UserMapper userMapper; + private final FileProperties properties; + private final RedisUtils redisUtils; + private final UserCacheClean userCacheClean; + private final OnlineUserService onlineUserService; + + @Override + public Object queryAll(UserQueryCriteria criteria, Pageable pageable) { + Page page = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable); + // 添加用户账户冻结状态 + Map map = PageUtil.toPage(page.map(userMapper::toDto)); + + List userDtoList = (List) map.get("content"); + if (ObjectUtil.isNotEmpty(userDtoList)) { + List list = new ArrayList(); + for (UserDto userDto : userDtoList) { + String key = String.format(RedisUtils.BLOCKED_ACCOUNT, userDto.getUsername()); + long expire = redisUtils.getExpire(key); + Integer blockedStatus = 0; + String blockedTime = ""; + if (expire > 0) { + blockedStatus = 1; + blockedTime = DateUtil.getHour(expire); + } + Map toMap = JSONUtil.parseObj(userDto); + toMap.put("blockedStatus", blockedStatus); + toMap.put("blockedTime", blockedTime); + list.add(toMap); + } + map.put("content", list); + } + + return map; + } + + @Override + public List queryAll(UserQueryCriteria criteria) { + List users = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)); + return userMapper.toDto(users); + } + + @Override + @Cacheable(key = "'id:' + #p0") + @Transactional(rollbackFor = Exception.class) + public UserDto findById(long id) { + User user = userRepository.findById(id).orElseGet(User::new); + ValidationUtil.isNull(user.getId(), "User", "id", id); + return userMapper.toDto(user); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(User resources) { + if (userRepository.findByUsername(resources.getUsername()) != null) { + throw new EntityExistException(User.class, "username", resources.getUsername()); + } + if (userRepository.findByEmail(resources.getEmail()) != null) { + throw new EntityExistException(User.class, "email", resources.getEmail()); + } + if (userRepository.findByPhone(resources.getPhone()) != null) { + throw new EntityExistException(User.class, "phone", resources.getPhone()); + } + userRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(User resources) throws Exception { + User user = userRepository.findById(resources.getId()).orElseGet(User::new); + ValidationUtil.isNull(user.getId(), "User", "id", resources.getId()); + User user1 = userRepository.findByUsername(resources.getUsername()); + User user2 = userRepository.findByEmail(resources.getEmail()); + User user3 = userRepository.findByPhone(resources.getPhone()); + if (user1 != null && !user.getId().equals(user1.getId())) { + throw new EntityExistException(User.class, "username", resources.getUsername()); + } + if (user2 != null && !user.getId().equals(user2.getId())) { + throw new EntityExistException(User.class, "email", resources.getEmail()); + } + if (user3 != null && !user.getId().equals(user3.getId())) { + throw new EntityExistException(User.class, "phone", resources.getPhone()); + } + // 如果用户的角色改变 + if (!resources.getRoles().equals(user.getRoles())) { + redisUtils.del(CacheKey.DATA_USER + resources.getId()); + redisUtils.del(CacheKey.MENU_USER + resources.getId()); + redisUtils.del(CacheKey.ROLE_AUTH + resources.getId()); + } + // 如果用户被禁用,则清除用户登录信息 + if(!resources.getEnabled()){ + onlineUserService.kickOutForUsername(resources.getUsername()); + } + user.setUsername(resources.getUsername()); + user.setEmail(resources.getEmail()); + user.setEnabled(resources.getEnabled()); + user.setRoles(resources.getRoles()); + user.setDept(resources.getDept()); + user.setJobs(resources.getJobs()); + user.setPhone(resources.getPhone()); + user.setNickName(resources.getNickName()); + user.setGender(resources.getGender()); + userRepository.save(user); + // 清除缓存 + delCaches(user.getId(), user.getUsername()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateCenter(User resources) { + User user = userRepository.findById(resources.getId()).orElseGet(User::new); + User user1 = userRepository.findByPhone(resources.getPhone()); + if (user1 != null && !user.getId().equals(user1.getId())) { + throw new EntityExistException(User.class, "phone", resources.getPhone()); + } + user.setNickName(resources.getNickName()); + user.setPhone(resources.getPhone()); + user.setGender(resources.getGender()); + userRepository.save(user); + // 清理缓存 + delCaches(user.getId(), user.getUsername()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + for (Long id : ids) { + // 清理缓存 + UserDto user = findById(id); + delCaches(user.getId(), user.getUsername()); + } + userRepository.deleteAllByIdIn(ids); + } + + @Override + public UserDto findByName(String userName) { + User user = userRepository.findByUsername(userName); + if (user == null) { + throw new EntityNotFoundException(User.class, "name", userName); + } else { + return userMapper.toDto(user); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updatePass(String username, String pass) { + userRepository.updatePass(username, pass, new Date()); + flushCache(username); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Map updateAvatar(MultipartFile multipartFile) { + // 文件大小验证 + FileUtil.checkSize(properties.getAvatarMaxSize(), multipartFile.getSize()); + // 验证文件上传的格式 + String image = "gif jpg png jpeg"; + String fileType = FileUtil.getExtensionName(multipartFile.getOriginalFilename()); + if(fileType != null && !image.contains(fileType)){ + throw new BadRequestException("文件格式错误!, 仅支持 " + image +" 格式"); + } + User user = userRepository.findByUsername(SecurityUtils.getCurrentUsername()); + String oldPath = user.getAvatarPath(); + File file = FileUtil.upload(multipartFile, properties.getPath().getAvatar()); + user.setAvatarPath(Objects.requireNonNull(file).getPath()); + user.setAvatarName(file.getName()); + userRepository.save(user); + if (StringUtils.isNotBlank(oldPath)) { + FileUtil.del(oldPath); + } + @NotBlank String username = user.getUsername(); + flushCache(username); + return new HashMap(1) {{ + put("avatar", file.getName()); + }}; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateEmail(String username, String email) { + userRepository.updateEmail(username, email); + flushCache(username); + } + + @Override + public void download(List queryAll, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (UserDto userDTO : queryAll) { + List roles = userDTO.getRoles().stream().map(RoleSmallDto::getName).collect(Collectors.toList()); + Map map = new LinkedHashMap<>(); + map.put("用户名", userDTO.getUsername()); + map.put("角色", roles); + map.put("部门", userDTO.getDept().getName()); + map.put("岗位", userDTO.getJobs().stream().map(JobSmallDto::getName).collect(Collectors.toList())); + map.put("邮箱", userDTO.getEmail()); + map.put("状态", userDTO.getEnabled() ? "启用" : "禁用"); + map.put("手机号码", userDTO.getPhone()); + map.put("修改密码的时间", userDTO.getPwdResetTime()); + map.put("创建日期", userDTO.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + /** + * 清理缓存 + * + * @param id / + */ + public void delCaches(Long id, String username) { + redisUtils.del(CacheKey.USER_ID + id); + flushCache(username); + } + + /** + * 清理 登陆时 用户缓存信息 + * + * @param username / + */ + private void flushCache(String username) { + userCacheClean.cleanUserCache(username); + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/VerifyServiceImpl.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/VerifyServiceImpl.java new file mode 100644 index 0000000..ec3230c --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/impl/VerifyServiceImpl.java @@ -0,0 +1,81 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.impl; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.extra.template.Template; +import cn.hutool.extra.template.TemplateConfig; +import cn.hutool.extra.template.TemplateEngine; +import cn.hutool.extra.template.TemplateUtil; +import lombok.RequiredArgsConstructor; +import me.zhengjie.domain.vo.EmailVo; +import me.zhengjie.exception.BadRequestException; +import me.zhengjie.modules.system.service.VerifyService; +import me.zhengjie.utils.RedisUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.util.Collections; + +/** + * @author Zheng Jie + * @date 2018-12-26 + */ +@Service +@RequiredArgsConstructor +public class VerifyServiceImpl implements VerifyService { + + @Value("${code.expiration}") + private Long expiration; + private final RedisUtils redisUtils; + + @Override + @Transactional(rollbackFor = Exception.class) + public EmailVo sendEmail(String email, String key) { + EmailVo emailVo; + String content; + String redisKey = key + email; + // 如果不存在有效的验证码,就创建一个新的 + TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH)); + Template template = engine.getTemplate("email/email.ftl"); + Object oldCode = redisUtils.get(redisKey); + if(oldCode == null){ + String code = RandomUtil.randomNumbers (6); + // 存入缓存 + if(!redisUtils.set(redisKey, code, expiration)){ + throw new BadRequestException("服务异常,请联系网站负责人"); + } + content = template.render(Dict.create().set("code",code)); + emailVo = new EmailVo(Collections.singletonList(email),"EL-ADMIN后台管理系统",content); + // 存在就再次发送原来的验证码 + } else { + content = template.render(Dict.create().set("code",oldCode)); + emailVo = new EmailVo(Collections.singletonList(email),"EL-ADMIN后台管理系统",content); + } + return emailVo; + } + + @Override + public void validated(String key, String code) { + Object value = redisUtils.get(key); + if(value == null || !value.toString().equals(code)){ + throw new BadRequestException("无效验证码"); + } else { + redisUtils.del(key); + } + } +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DeptMapper.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DeptMapper.java new file mode 100644 index 0000000..b0fb904 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DeptMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.modules.system.domain.Dept; +import me.zhengjie.modules.system.service.dto.DeptDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author Zheng Jie +* @date 2019-03-25 +*/ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DeptMapper extends BaseMapper { +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DeptSmallMapper.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DeptSmallMapper.java new file mode 100644 index 0000000..7507600 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DeptSmallMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.modules.system.domain.Dept; +import me.zhengjie.modules.system.service.dto.DeptSmallDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author Zheng Jie +* @date 2019-03-25 +*/ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DeptSmallMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DictDetailMapper.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DictDetailMapper.java new file mode 100644 index 0000000..3f9fe84 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DictDetailMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.modules.system.domain.DictDetail; +import me.zhengjie.modules.system.service.dto.DictDetailDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Mapper(componentModel = "spring", uses = {DictSmallMapper.class}, unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DictDetailMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DictMapper.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DictMapper.java new file mode 100644 index 0000000..1047b3b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DictMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.modules.system.domain.Dict; +import me.zhengjie.modules.system.service.dto.DictDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DictMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DictSmallMapper.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DictSmallMapper.java new file mode 100644 index 0000000..80ccc4e --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/DictSmallMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.modules.system.domain.Dict; +import me.zhengjie.modules.system.service.dto.DictSmallDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DictSmallMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/JobMapper.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/JobMapper.java new file mode 100644 index 0000000..3771930 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/JobMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.modules.system.domain.Job; +import me.zhengjie.modules.system.service.dto.JobDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author Zheng Jie +* @date 2019-03-29 +*/ +@Mapper(componentModel = "spring",uses = {DeptMapper.class},unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface JobMapper extends BaseMapper { +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/JobSmallMapper.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/JobSmallMapper.java new file mode 100644 index 0000000..36a59cf --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/JobSmallMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.modules.system.domain.Job; +import me.zhengjie.modules.system.service.dto.JobSmallDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author Zheng Jie +* @date 2019-03-29 +*/ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface JobSmallMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/MenuMapper.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/MenuMapper.java new file mode 100644 index 0000000..6d8bffa --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/MenuMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.modules.system.domain.Menu; +import me.zhengjie.modules.system.service.dto.MenuDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** + * @author Zheng Jie + * @date 2018-12-17 + */ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface MenuMapper extends BaseMapper { +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/RoleMapper.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/RoleMapper.java new file mode 100644 index 0000000..5dc551d --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/RoleMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.modules.system.domain.Role; +import me.zhengjie.modules.system.service.dto.RoleDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Mapper(componentModel = "spring", uses = {MenuMapper.class, DeptMapper.class}, unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface RoleMapper extends BaseMapper { + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/RoleSmallMapper.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/RoleSmallMapper.java new file mode 100644 index 0000000..db034b5 --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/RoleSmallMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.modules.system.domain.Role; +import me.zhengjie.modules.system.service.dto.RoleSmallDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** + * @author Zheng Jie + * @date 2019-5-23 + */ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface RoleSmallMapper extends BaseMapper { + +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/UserMapper.java b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/UserMapper.java new file mode 100644 index 0000000..510c21b --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/UserMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.modules.system.domain.User; +import me.zhengjie.modules.system.service.dto.UserDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Mapper(componentModel = "spring",uses = {RoleMapper.class, DeptMapper.class, JobMapper.class},unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface UserMapper extends BaseMapper { +} diff --git a/wjcy-system/src/main/java/me/zhengjie/modules/utils/GoogleAuthenticatorUtil.java b/wjcy-system/src/main/java/me/zhengjie/modules/utils/GoogleAuthenticatorUtil.java new file mode 100644 index 0000000..0861ddf --- /dev/null +++ b/wjcy-system/src/main/java/me/zhengjie/modules/utils/GoogleAuthenticatorUtil.java @@ -0,0 +1,179 @@ +package me.zhengjie.modules.utils; + +import cn.hutool.core.util.ObjectUtil; +import me.zhengjie.config.GoogleAuthProperties; +import me.zhengjie.utils.RedisUtils; +import org.apache.commons.codec.binary.Base32; +import org.apache.commons.codec.binary.Base64; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +/** + *

+ * Google Authenticator 工具类 + *

+ * + * @author: rch + * @since: 2020-08-25 + */ +@Component +public class GoogleAuthenticatorUtil { + + private static RedisUtils redisUtils; + @Resource(name = "redisUtils") + public void setRedisUtils(RedisUtils redisUtils) { + GoogleAuthenticatorUtil.redisUtils = redisUtils; + } + + /** default 3 - max 17 (from google docs)最多可偏移的时间 */ + int window_size = 0; + + public void setWindowSize(int s) { + if (s >= 1 && s <= 17) { + window_size = s; + } + } + + /** + * 验证身份验证码是否正确 + * + * @param codes + * 输入的身份验证码 + * @param savedSecret + * 密钥 + * @return + */ + public static Boolean authcode(String codes, String savedSecret) { + long code = 0; + try { + code = Long.parseLong(codes); + } catch (Exception e) { + e.printStackTrace(); + } + long t = System.currentTimeMillis(); + GoogleAuthenticatorUtil ga = new GoogleAuthenticatorUtil(); + // should give 5 * 30 seconds of grace... + ga.setWindowSize(GoogleAuthProperties.WINDOW_SIZE); + boolean r = ga.check_code(savedSecret, code, t); + return r; + } + + /** + * 获取密钥 + * + * @param user + * 用户 + * @param host + * 域 + * @return 密钥 + */ + public static String genSecret(String user, String host) { + + String secretKey = GoogleAuthProperties.REDIS_GOOGLE_AUTH_KEY + "_" + GoogleAuthProperties.SEED + "_" + user; + Object secretValue = redisUtils.get(secretKey); + if (ObjectUtil.isEmpty(secretValue)) { + String secret = generateSecretKey(); + getQRBarcodeURL(user, host, secret); + secretValue = secret; + redisUtils.set(secretKey, secret); + } + + return secretValue.toString(); + } + + private static String generateSecretKey() { + SecureRandom sr = null; + try { + sr = SecureRandom.getInstance(GoogleAuthProperties.RANDOM_NUMBER_ALGORITHM); + sr.setSeed(Base64.decodeBase64(GoogleAuthProperties.SEED)); + byte[] buffer = sr.generateSeed(GoogleAuthProperties.SECRET_SIZE); + Base32 codec = new Base32(); + byte[] bEncodedKey = codec.encode(buffer); + String encodedKey = new String(bEncodedKey); + return encodedKey; + } catch (NoSuchAlgorithmException e) { + // should never occur... configuration error + } + return null; + } + + /** + * 获取二维码图片URL + * + * @param user + * 用户 + * @param host + * 域 + * @param secret + * 密钥 + * @return 二维码URL + */ + public static String getQRBarcodeURL(String user, String host, String secret) { + return String.format(GoogleAuthProperties.QR_CREATE_PREFIX_URL, user, host, secret); + } + + private boolean check_code(String secret, long code, long timeMsec) { + Base32 codec = new Base32(); + byte[] decodedKey = codec.decode(secret); + long t = (timeMsec / 1000L) / 30L; + for (int i = -window_size; i <= window_size; ++i) { + long hash; + try { + hash = verify_code(decodedKey, t + i); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e.getMessage()); + } + if (hash == code) { + return true; + } + } + return false; + } + + private static int verify_code(byte[] key, long t) + throws NoSuchAlgorithmException, InvalidKeyException { + byte[] data = new byte[8]; + long value = t; + for (int i = 8; i-- > 0; value >>>= 8) { + data[i] = (byte) value; + } + SecretKeySpec signKey = new SecretKeySpec(key, "HmacSHA1"); + Mac mac = Mac.getInstance("HmacSHA1"); + mac.init(signKey); + byte[] hash = mac.doFinal(data); + int offset = hash[20 - 1] & 0xF; + long truncatedHash = 0; + for (int i = 0; i < 4; ++i) { + truncatedHash <<= 8; + truncatedHash |= (hash[offset + i] & 0xFF); + } + truncatedHash &= 0x7FFFFFFF; + truncatedHash %= 1000000; + return (int) truncatedHash; + } + + public static void main(String[] args) { + /* + * 注意:先运行前两步,获取密钥和二维码url。 然后只运行第三步,填写需要验证的验证码,和第一步生成的密钥 + */ + String user = "testUser"; + String host = "testHost"; + // 第一步:获取密钥 + String secret = genSecret(user, host); + System.out.println("secret:" + secret); + // 第二步:根据密钥获取二维码图片url(可忽略) + String url = getQRBarcodeURL(user, host, secret); + System.out.println("url:" + url); + // 第三步:验证(第一个参数是需要验证的验证码,第二个参数是第一步生成的secret运行) + boolean result = authcode("271239", "OHXU6PLMZMDJIDY6"); + System.out.println("result:" + result); + } +} + diff --git a/wjcy-system/src/main/resources/banner.txt b/wjcy-system/src/main/resources/banner.txt new file mode 100644 index 0000000..d0f401a --- /dev/null +++ b/wjcy-system/src/main/resources/banner.txt @@ -0,0 +1,8 @@ + _ _ _ + | | | | (_) + ___| |______ __ _ __| |_ __ ___ _ _ __ + / _ | |______/ _` |/ _` | '_ ` _ \| | '_ \ + | __| | | (_| | (_| | | | | | | | | | | + \___|_| \__,_|\__,_|_| |_| |_|_|_| |_| + + :: Spring Boot :: (v2.1.0.RELEASE) \ No newline at end of file diff --git a/wjcy-system/src/main/resources/config/application-dev.yml b/wjcy-system/src/main/resources/config/application-dev.yml new file mode 100644 index 0000000..81d0a99 --- /dev/null +++ b/wjcy-system/src/main/resources/config/application-dev.yml @@ -0,0 +1,285 @@ +#配置数据源 +spring: + datasource: + druid: + db-type: com.alibaba.druid.pool.DruidDataSource + driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy + url: jdbc:log4jdbc:mysql://192.168.10.136:3306/wjcy?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false +# url: jdbc:log4jdbc:mysql://192.168.10.85:3306/wjcy?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false + username: root + password: wjcy@123456 +# url: jdbc:log4jdbc:mysql://120.77.145.59:3306/wjcy_2?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false +# username: root +# password: 416909 + # 初始连接数 + initial-size: 5 + # 最小连接数 + min-idle: 15 + # 最大连接数 + max-active: 30 + # 超时时间(以秒数为单位) + remove-abandoned-timeout: 180 + # 获取连接超时时间 + max-wait: 3000 + # 连接有效性检测时间 + time-between-eviction-runs-millis: 60000 + # 连接在池中最小生存的时间 + min-evictable-idle-time-millis: 300000 + # 连接在池中最大生存的时间 + max-evictable-idle-time-millis: 900000 + # 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除 + test-while-idle: true + # 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个 + test-on-borrow: true + # 是否在归还到池中前进行检验 + test-on-return: false + # 检测连接是否有效 + validation-query: select 1 + # 配置监控统计 + webStatFilter: + enabled: true + stat-view-servlet: + enabled: true + url-pattern: /druid/* + reset-enable: false + filter: + stat: + enabled: true + # 记录慢SQL + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + config: + multi-statement-allow: true + slf4j: + enabled: true + statement-create-after-log-enabled: false + statement-close-after-log-enabled: false + result-set-open-after-log-enabled: false + result-set-close-after-log-enabled: false + result-set-next-after-log-enabled: false + + redis: + #数据库索引 + database: 13 + host: 192.168.10.136 + port: 6379 + password: wjcy@123456 +# host: 120.77.145.59 +# port: 6379 +# password: 416909 + #连接超时时间 + timeout: 5000 + #过期时间 1个月(60*60*24*30) + expired: 2592000 + + mvc: + view: + prefix: classpath:/templates/ + suffix: .html + thymeleaf: + cache: false + +knife4j: + enable: true + basic: + enable: true + username: wjcy + password: 123456 + + +logging: + config: classpath:log4j2.xml + level: + me.zhengjie: debug + +#Mybatis plus 配置 +mybatis-plus: + # 映射文件所在路径 + mapper-locations: classpath*:me/zhengjie/dao/mapper/*.xml + # pojo类所在包路径 + #typeAliasesPackage: + # 开启驼峰命名规则自动转换 + configuration: + map-underscore-to-camel-case: true + log-impl: org.apache.ibatis.logging.log4j2.Log4j2Impl + global-config: + db-config: + # 配置表明前缀,例如表设计时表名为tb_manager,对应entity为Manager + #table-prefix: tb_ + #逻辑已删除值 + logic-delete-value: 1 + #逻辑未删除值 + logic-not-delete-value: 0 + # 是否开启like查询,即对 stirng 字段是否使用 like,默认不开启 + column-like: true + +# 登录相关配置 +login: + # 登录缓存 + cache-enable: true + # 是否限制单用户登录 + single-login: false + # 验证码 + login-code: + # 验证码类型配置 查看 LoginProperties 类 + code-type: arithmetic + # 登录图形验证码有效时间/分钟 + expiration: 2 + # 验证码高度 + width: 111 + # 验证码宽度 + height: 36 + # 内容长度 + length: 2 + # 字体名称,为空则使用默认字体 + font-name: + # 字体大小 + font-size: 25 + +#jwt +jwt: + header: Authorization + # 令牌前缀 + token-start-with: Bearer + # 必须使用最少88位的Base64对该令牌进行编码 + base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI= + # 令牌过期时间 此处单位/毫秒 ,默认4小时,可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html + token-validity-in-seconds: 14400000 + # 在线用户key + online-key: online-token- + # 验证码 + code-key: code-key- + # token 续期检查时间范围(默认30分钟,单位毫秒),在token即将过期的一段时间内用户操作了,则给用户的token续期 + detect: 1800000 + # 续期时间范围,默认1小时,单位毫秒 + renew: 3600000 + +#是否允许生成代码,生产环境设置为false +generator: + enabled: true + +#是否开启 swagger-ui +swagger: + enabled: true + +# IP 本地解析 +ip: + local-parsing: true + +# 文件存储路径 +file: + mac: + path: ~/file/ + avatar: ~/avatar/ + linux: + path: /home/luckyDraw/file/ + avatar: /home/luckyDraw/avatar/ + windows: + path: E:\wjcyFileSpace\file\ + avatar: E:\wjcyFileSpace\avatar\ + # 文件大小 /M + maxSize: 100 + avatarMaxSize: 5 + + +system: + imgPath: E:\wjcyFileSpace\file + # 静态资源访问路径(返回前端时添加) +# fileVisitAddr: http://www.images.com + fileVisitAddr: http://localhost:8008/file + #文件上传接口后缀,用来放行xss过滤 + uploadSuffix: file/uploadFile + # 单文件上传大小限制,单位 :MB + maxFileSize: 10 + # 视频单文件上传限制,单位 :MB + maxVideoFileSize: 25 + # ip库文件的绝对路径 window 就是指到resource下的ip2region下 + ip2regionDbPath: E:\CodeWorkSpace\wjcy\wjcy-system\src\main\resources\ip2region\ip2region.db + # 多语言文件路径 + languagePath: /home/waguda/wjcy/language + +config: + # 放掉的api 校验token huijia@biying123 - https://md5jiami.51240.com/ + apiToken: "e6f5e41ca6b103070ff89c812a36eaec" + #文件上传前缀(首位+'/' 末尾不加'/'),用来放行静态资源访问权限(图片,音频等) + uploadPrefix: /capital + # 图片上传保存路径(注意格式,首尾带‘/’) key:图片上传类型 value: + uploadImgPath: + # 用户头像修改 + 1: /wjcy/img/ + 2: /wjcy/rotation/ + 3: /wjcy/article/ + 4: /wjcy/currency/ + # 提现审核提示音 + 5: /wjcy/tones/ + # 聊天室默认头像 + 6: /wjcy/chat/head/ + # 聊天室会员上传的图片 + 7: /wjcy/chat/img/ + # 聊天室会员上传视频 + 8: /wjcy/chat/video/ + 9: /wjcy/promotion/ + # excel + 10: /wjcy/excel/ + 11: /wjcy/export/ + 12: /wjcy/wellReceived/ + 13: /wjcy/dhWellReceived/ + # 支持文件上传的文件格式 + sustainImgFormat: + - img + - jpg + - png + - mp3 + - pem + - jpeg + - gif + - JPG + - JPEG + - PNG + - AVI + - mov + - rmvb + - rm + - FLV + - mp4 + - 3GP + - zip + - xlsx + +# Goole Auth +auth: + secret_size: 10 + seed: g8GjEvTbW5oVSV7avLBdwIHqGlUYNzKFI7izOF8GwLDVKs2m0QN7vxRs2im5MDaNCWGmcD2rvcZx + random_number_algorithm: SHA1PRNG + window_size: 0 + redis_google_auth_key: googelAuthKey + qr_create_prefix_url: https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=otpauth://totp/%s@%s?secret=%s + + +#敦煌api 请求参数 +dh: + access_token: 0QkUo9opYCcmB0UMzqK2XKFFNDDvlpmpRYyDkcVJ + buy_order_url: http://api.dhgate.com/dop/router + buy_order_method: dh.buyer.order.place + buy_order_v: 2.0 + pay_order_url: http://api.dhgate.com/dop/router + pay_order_method: dh.buyer.order.pay + pay_order_v: 1.0 + +# 平台配置 +plats: + dh: + buyOrderUrl: http://api.dhgate.com/dop/router + buyOrderMethod: dh.buyer.order.place + buyOrderv: 2.0 + payOrder_url: http://api.dhgate.com/dop/router + payOrderMethod: dh.buyer.order.pay + payOrderv: 1.0 + +# 影刀 +yd: + accessKeyId: navkbKspVWfjPgm6@platform + accessKeySecret: SuUc0zMfhrQX594eJnwFPm1sqk8CYtNv + callback: http://test.vogocm.com:8008/api/yd/callback diff --git a/wjcy-system/src/main/resources/config/application-local.yml b/wjcy-system/src/main/resources/config/application-local.yml new file mode 100644 index 0000000..262baba --- /dev/null +++ b/wjcy-system/src/main/resources/config/application-local.yml @@ -0,0 +1,411 @@ +#配置数据源 +spring: + datasource: + druid: + db-type: com.alibaba.druid.pool.DruidDataSource + driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy + url: jdbc:log4jdbc:mysql://192.168.110.108:3306/jlt_capiltal_xxs5?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false + username: root + password: root + # 初始连接数 + initial-size: 5 + # 最小连接数 + min-idle: 15 + # 最大连接数 + max-active: 30 + # 超时时间(以秒数为单位) + remove-abandoned-timeout: 180 + # 获取连接超时时间 + max-wait: 3000 + # 连接有效性检测时间 + time-between-eviction-runs-millis: 60000 + # 连接在池中最小生存的时间 + min-evictable-idle-time-millis: 300000 + # 连接在池中最大生存的时间 + max-evictable-idle-time-millis: 900000 + # 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除 + test-while-idle: true + # 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个 + test-on-borrow: true + # 是否在归还到池中前进行检验 + test-on-return: false + # 检测连接是否有效 + validation-query: select 1 + # 配置监控统计 + webStatFilter: + enabled: true + stat-view-servlet: + enabled: true + url-pattern: /druid/* + reset-enable: false + filter: + stat: + enabled: true + # 记录慢SQL + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + config: + multi-statement-allow: true + slf4j: + enabled: true + statement-create-after-log-enabled: false + statement-close-after-log-enabled: false + result-set-open-after-log-enabled: false + result-set-close-after-log-enabled: false + result-set-next-after-log-enabled: false + + redis: + #数据库索引 + database: 12 + host: 192.168.110.108 + port: 6379 + password: tiyu!tiyu! + #连接超时时间 + timeout: 5000 + #过期时间 1个月(60*60*24*30) + expired: 2592000 + + mvc: + view: + prefix: classpath:/templates/ + suffix: .html + thymeleaf: + cache: false + + +logging: + config: classpath:log4j2.xml + level: + me.zhengjie: debug + +#Mybatis plus 配置 +mybatis-plus: + # 映射文件所在路径 + mapper-locations: classpath*:me/zhengjie/dao/mapper/*.xml + # pojo类所在包路径 + #typeAliasesPackage: + # 开启驼峰命名规则自动转换 + configuration: + map-underscore-to-camel-case: true + log-impl: org.apache.ibatis.logging.log4j2.Log4j2Impl + global-config: + db-config: + # 配置表明前缀,例如表设计时表名为tb_manager,对应entity为Manager + #table-prefix: tb_ + #逻辑已删除值 + logic-delete-value: 1 + #逻辑未删除值 + logic-not-delete-value: 0 + # 是否开启like查询,即对 stirng 字段是否使用 like,默认不开启 + column-like: true + +# 登录相关配置 +login: + # 登录缓存 + cache-enable: true + # 是否限制单用户登录 + single-login: false + # 验证码 + login-code: + # 验证码类型配置 查看 LoginProperties 类 + code-type: arithmetic + # 登录图形验证码有效时间/分钟 + expiration: 2 + # 验证码高度 + width: 111 + # 验证码宽度 + height: 36 + # 内容长度 + length: 2 + # 字体名称,为空则使用默认字体 + font-name: + # 字体大小 + font-size: 25 + +#jwt +jwt: + header: Authorization + # 令牌前缀 + token-start-with: Bearer + # 必须使用最少88位的Base64对该令牌进行编码 + base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI= + # 令牌过期时间 此处单位/毫秒 ,默认4小时,可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html + token-validity-in-seconds: 14400000 + # 在线用户key + online-key: online-token- + # 验证码 + code-key: code-key- + # token 续期检查时间范围(默认30分钟,单位毫秒),在token即将过期的一段时间内用户操作了,则给用户的token续期 + detect: 1800000 + # 续期时间范围,默认1小时,单位毫秒 + renew: 3600000 + +#是否允许生成代码,生产环境设置为false +generator: + enabled: true + +#是否开启 swagger-ui +swagger: + enabled: true + +# IP 本地解析 +ip: + local-parsing: true + +# 文件存储路径 +file: + mac: + path: ~/file/ + avatar: ~/avatar/ + linux: + path: /home/luckyDraw/file/ + avatar: /home/luckyDraw/avatar/ + windows: + path: C:\luckyDraw\file\ + avatar: C:\luckyDraw\avatar\ + # 文件大小 /M + maxSize: 100 + avatarMaxSize: 5 + + +system: + imgPath: /home/waguda/capiltal/file/ + # 静态资源访问路径(返回前端时添加) + fileVisitAddr: http://img.com + #文件上传接口后缀,用来放行xss过滤 + uploadSuffix: file/uploadFile + # 单文件上传大小限制,单位 :MB + maxFileSize: 10 + # 视频单文件上传限制,单位 :MB + maxVideoFileSize: 25 + # ip库文件的绝对路径 window 就是指到resource下的ip2region下 + ip2regionDbPath: /home/work/services/capiltal/capiltal-system/ip2region/ip2region.db + # 多语言文件路径 + languagePath: /home/waguda/capiltal/language + wsUrl: ws://192.168.110.99:8110 + # 百度翻译 APPID + baiduAppId: 20211116001000718 + # 百度翻译privateKey + baiduPrivateKey: jSDxw0_QkRnbRdRT0rKY + +config: + # 放掉的api 校验token huijia@biying123 - https://md5jiami.51240.com/ + apiToken: "e6f5e41ca6b103070ff89c812a36eaec" + #文件上传前缀(首位+'/' 末尾不加'/'),用来放行静态资源访问权限(图片,音频等) + uploadPrefix: /capital + # 图片上传保存路径(注意格式,首尾带‘/’) key:图片上传类型 value: + uploadImgPath: + # 用户头像修改 + 1: /capital/img/ + 2: /capital/rotation/ + 3: /capital/article/ + 4: /capital/currency/ + + # 支持文件上传的文件格式 + sustainImgFormat: + - img + - jpg + - png + - mp3 + - pem + - jpeg + - gif + - JPG + - JPEG + - PNG + - AVI + - mov + - rmvb + - rm + - FLV + - mp4 + - 3GP + - zip + +web3j: + # web3j 区块链信息 + linkAddress: + #火币 + - name: HECO + # 服务实现类全限定类名 + serverName: "me.zhengjie.web3j.service.impl.ETHBlockchainServiceImpl" + # rpc 连接地址 + url: https://http-testnet.hecochain.com + # 官网域名+查询交易明细 + domain: https://testnet.hecoinfo.com/tx + # 链路Id,必须以 0x开头 + chainId: "0x100" + #合约币种 + contracts: + USDT: + address: "0x425a2d7c3df8a7872f05405dc6e34b6d9cd714be" + accuracy: 18 + MDX: + address: "0x30e552B5Ce0495A55b9138343dD88d6457a6C66b" + accuracy: 18 + DMT: + address: "0x4da2F416aa79fB0BeCA3D6cf6EB6Fe86b4a747CF" + accuracy: 18 + + # ok链 + - name: OKEX + # 服务实现类全限定类名 + serverName: "me.zhengjie.web3j.service.impl.ETHBlockchainServiceImpl" + # rpc 连接地址 + url: https://exchaintestrpc.okex.org + # 官网域名+查询交易明细 + domain: https://www.oklink.com/zh-cn/oec-test/tx + # 链路Id,必须以 0x开头 + chainId: "0x41" + #合约币种 + contracts: + USDT: + address: "0x1328bB18fe06647878d04fcB94BA5474c85C7616" + accuracy: 18 + MDX: + address: "" + accuracy: 0 + DMT: + address: "" + accuracy: 0 + + # 币安链 + - name: BNB + # 服务实现类全限定类名 + serverName: "me.zhengjie.web3j.service.impl.ETHBlockchainServiceImpl" + # rpc 连接地址 https://data-seed-prebsc-1-s1.binance.org:8545/ https://data-seed-prebsc-2-s3.binance.org:8545 + url: https://data-seed-prebsc-1-s1.binance.org:8545/ + # 官网域名+查询交易明细 + domain: https://testnet.bscscan.com/tx + # 链路Id,必须以 0x开头 + chainId: "0x61" + #合约币种 + contracts: + USDT: + # address: "0x3D39e763d2942816c96E783bb53C7c5DB44AFFF3" + address: "0xA12327AaE5C6CCcf816bAC49136f050FeFe89CB6" + accuracy: 18 + MDX: + address: "0x79CA70F863c4273Bb276F37381e1aD2096b77CeE" + accuracy: 18 + ETH: + address: "0x19E6689Bb9CF7Ef04AFf57B77562E4C943c415cD" + accuracy: 18 + CAKE: + address: "0xeBb3CD5EF4a5875AEfcf02CeAaa77Ac8A164523f" + accuracy: 18 + + # 波场 + - name: TRON + # 服务实现类全限定类名 + serverName: "me.zhengjie.web3j.service.impl.TronBlockchainServiceImpl" + # rpc 连接地址, 可选: mainnet、shasta、nile,或其他节点(例:47.252.19.181) + network: shasta + # http接口请求的URL + url: https://api.shasta.trongrid.io + # 官网域名+查询交易明细 + domain: https://shasta.tronscan.org//#/transaction + # 私钥,波场调用API时,不管什么接口都必须要设置私钥 + hexPrivateKey: "780e0d9997862dfac8e0698c8dd457531c9c13ecf6cec377315e95c30b43c8c4" + # 说明:https://cn.developers.tron.network/reference/%E4%BB%80%E4%B9%88%E6%98%AFapi-key e3506c97-a4b6-4bf7-829a-6a5d48b112f7 + apiKey: "" + #合约币种 + contracts: + USDT: + # TNuoKL1ni8aoshfFL1ASca1Gou9RXwAzfn USDT:TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf + address: "TNpzntv25qsy1HVWQW2jCrhWj5wad3tVcj" + accuracy: 10 + MDX: + address: "" + accuracy: 0 + DMT: + address: "" + accuracy: 0 + + blockchain: + 1: + - currencyType: 1 + name: USDT + - currencyType: 2 + name: MDX + - currencyType: 3 + name: DMT + 2: + - currencyType: 1 + name: USDT + 4: + - currencyType: 1 + name: USDT + - currencyType: 2 + name: MDX + - currencyType: 5 + name: ETH + - currencyType: 4 + name: CAKE + 5: + - currencyType: 1 + name: USDT + +# 采集开奖结果配置 +draw: + config: + configs: + - passType: 1 #链路 火币链 + currency: BTC #采集币种 BTC + url: https://api.huobi.pro/market/history/kline #采集地址 + period: 1min #采集周期 1min, 5min, 15min, 30min, ---- 60min, 4hour, 1day, 1mon, 1week, 1year + symbol: btcusdt #交易对 btcusdt, ethbtc + size: 10 #返回数据条数 1 - 2000 + - passType: 4 #链路 币安链 + currency: BTC #采集币种 BTC + url: https://api.binance.com/api/v3/klines #采集地址 + period: 1m #采集周期 #采集周期 1m, 3m, 5m, 15m, 30m, ---- 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M + symbol: BTCUSDT #交易对 + size: 10 #返回数据条数 1 - 1000 + + + + +#该应用是否启用生产者 +rocketmq: + producer: + isOnOff: on + #发送同一类消息的设置为同一个group,保证唯一,默认不需要设置,rocketmq会使用ip@pid(pid代表jvm名字)作为唯一标示 + groupName: springboot-rocketmq-producer-capiltal + #mq的nameserver地址 43.240.95.168 + namesrvAddr: 192.168.110.108:9876 + #消息最大长度 默认1024*4(4M) + maxMessageSize: 4096 + #发送消息超时时间,默认3000 + sendMsgTimeout: 3000 + #发送消息失败重试次数,默认2 + retryTimesWhenSendFailed: 2 + consumer: + isOnOff: on + groupName: springboot-rocketmq-consumer-capiltal + #mq的nameserver地址 43.240.95.168 + namesrvAddr: 192.168.110.108:9876 + #该消费者订阅的主题和tags("*"号表示订阅该主题下所有的tags),格式:topic~tag1||tag2||tag3;topic2~*; + topics: capiltal-settlement-top~*;capiltal-statistics-member-top~* + consumeThreadMin: 20 + consumeThreadMax: 64 + #设置一次消费消息的条数,默认为1条 + consumeMessageBatchMaxSize: 1 + + +#Goole Auth +auth: + secret_size: 10 + seed: g8GjEvTbW5oVSV7avLBdwIHqGlUYNzKFI7izOF8GwLDVKs2m0QN7vxRs2im5MDaNCWGmcD2rvcZx + random_number_algorithm: SHA1PRNG + window_size: 0 + redis_google_auth_key: googelAuthKey + qr_create_prefix_url: https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=otpauth://totp/%s@%s?secret=%s + +telegram: + bot: + username: capiltal_uat_bot + token: 5008414161:AAHflrbo2v0DN8hpLhZAg5gC787yxFloWlk + chatId: -665412272 \ No newline at end of file diff --git a/wjcy-system/src/main/resources/config/application-prod.yml b/wjcy-system/src/main/resources/config/application-prod.yml new file mode 100644 index 0000000..08396dc --- /dev/null +++ b/wjcy-system/src/main/resources/config/application-prod.yml @@ -0,0 +1,250 @@ +#配置数据源 +spring: + datasource: + druid: + db-type: com.alibaba.druid.pool.DruidDataSource + driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy + url: jdbc:log4jdbc:mysql://mysql:3306/wjcy?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false + username: root + password: wjcy@123456 + # 初始连接数 + initial-size: 5 + # 最小连接数 + min-idle: 15 + # 最大连接数 + max-active: 30 + # 超时时间(以秒数为单位) + remove-abandoned-timeout: 180 + # 获取连接超时时间 + max-wait: 3000 + # 连接有效性检测时间 + time-between-eviction-runs-millis: 60000 + # 连接在池中最小生存的时间 + min-evictable-idle-time-millis: 300000 + # 连接在池中最大生存的时间 + max-evictable-idle-time-millis: 900000 + # 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除 + test-while-idle: true + # 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个 + test-on-borrow: true + # 是否在归还到池中前进行检验 + test-on-return: false + # 检测连接是否有效 + validation-query: select 1 + # 配置监控统计 + webStatFilter: + enabled: true + stat-view-servlet: + enabled: true + url-pattern: /druid/* + reset-enable: false + filter: + stat: + enabled: true + # 记录慢SQL + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + config: + multi-statement-allow: true + slf4j: + enabled: true + statement-create-after-log-enabled: false + statement-close-after-log-enabled: false + result-set-open-after-log-enabled: false + result-set-close-after-log-enabled: false + result-set-next-after-log-enabled: false + + redis: + #数据库索引 + database: 12 + host: redis + port: 6379 + password: wjcy@123456 + #连接超时时间 + timeout: 5000 + #过期时间 1个月(60*60*24*30) + expired: 2592000 + + mvc: + view: + prefix: classpath:/templates/ + suffix: .html + thymeleaf: + cache: false + + +logging: + config: classpath:log4j2.xml + level: + me.zhengjie: debug + +#Mybatis plus 配置 +mybatis-plus: + # 映射文件所在路径 + mapper-locations: classpath*:me/zhengjie/dao/mapper/*.xml + # pojo类所在包路径 + #typeAliasesPackage: + # 开启驼峰命名规则自动转换 + configuration: + map-underscore-to-camel-case: true + log-impl: org.apache.ibatis.logging.log4j2.Log4j2Impl + global-config: + db-config: + # 配置表明前缀,例如表设计时表名为tb_manager,对应entity为Manager + #table-prefix: tb_ + #逻辑已删除值 + logic-delete-value: 1 + #逻辑未删除值 + logic-not-delete-value: 0 + # 是否开启like查询,即对 stirng 字段是否使用 like,默认不开启 + column-like: true + +# 登录相关配置 +login: + # 登录缓存 + cache-enable: true + # 是否限制单用户登录 + single-login: false + # 验证码 + login-code: + # 验证码类型配置 查看 LoginProperties 类 + code-type: arithmetic + # 登录图形验证码有效时间/分钟 + expiration: 2 + # 验证码高度 + width: 111 + # 验证码宽度 + height: 36 + # 内容长度 + length: 2 + # 字体名称,为空则使用默认字体 + font-name: + # 字体大小 + font-size: 25 + +#jwt +jwt: + header: Authorization + # 令牌前缀 + token-start-with: Bearer + # 必须使用最少88位的Base64对该令牌进行编码 + base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI= + # 令牌过期时间 此处单位/毫秒 ,默认4小时,可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html + token-validity-in-seconds: 14400000 + # 在线用户key + online-key: online-token- + # 验证码 + code-key: code-key- + # token 续期检查时间范围(默认30分钟,单位毫秒),在token即将过期的一段时间内用户操作了,则给用户的token续期 + detect: 1800000 + # 续期时间范围,默认1小时,单位毫秒 + renew: 3600000 + +#是否允许生成代码,生产环境设置为false +generator: + enabled: true + +#是否开启 swagger-ui +swagger: + enabled: true + +# IP 本地解析 +ip: + local-parsing: true + +# 文件存储路径 +file: + mac: + path: ~/file/ + avatar: ~/avatar/ + linux: + path: /home/luckyDraw/file/ + avatar: /home/luckyDraw/avatar/ + windows: + path: C:\luckyDraw\file\ + avatar: C:\luckyDraw\avatar\ + # 文件大小 /M + maxSize: 100 + avatarMaxSize: 5 + + +system: + imgPath: /home/work/wjcy/file + # 静态资源访问路径(返回前端时添加) + fileVisitAddr: http://img.com + #文件上传接口后缀,用来放行xss过滤 + uploadSuffix: file/uploadFile + # 单文件上传大小限制,单位 :MB + maxFileSize: 10 + # 视频单文件上传限制,单位 :MB + maxVideoFileSize: 25 + # ip库文件的绝对路径 window 就是指到resource下的ip2region下 + ip2regionDbPath: /home/work/wjcy/wjcy-system/src/main/resources/ip2region/ip2region.db + # 多语言文件路径 + languagePath: /home/work/wjcy/wjcy-system/language + +config: + # 放掉的api 校验token huijia@biying123 - https://md5jiami.51240.com/ + apiToken: "e6f5e41ca6b103070ff89c812a36eaec" + #文件上传前缀(首位+'/' 末尾不加'/'),用来放行静态资源访问权限(图片,音频等) + uploadPrefix: /capital + # 图片上传保存路径(注意格式,首尾带‘/’) key:图片上传类型 value: + uploadImgPath: + # 用户头像修改 + 1: /wjcy/img/ + 2: /wjcy/rotation/ + 3: /wjcy/article/ + 4: /wjcy/currency/ + # 提现审核提示音 + 5: /wjcy/tones/ + # 聊天室默认头像 + 6: /wjcy/chat/head/ + # 聊天室会员上传的图片 + 7: /wjcy/chat/img/ + # 聊天室会员上传视频 + 8: /wjcy/chat/video/ + 9: /wjcy/promotion/ + # excel + 10: /wjcy/excel/ + # 支持文件上传的文件格式 + sustainImgFormat: + - img + - jpg + - png + - mp3 + - pem + - jpeg + - gif + - JPG + - JPEG + - PNG + - AVI + - mov + - rmvb + - rm + - FLV + - mp4 + - 3GP + - zip + - xlsx + +# Goole Auth +auth: + secret_size: 10 + seed: g8GjEvTbW5oVSV7avLBdwIHqGlUYNzKFI7izOF8GwLDVKs2m0QN7vxRs2im5MDaNCWGmcD2rvcZx + random_number_algorithm: SHA1PRNG + window_size: 0 + redis_google_auth_key: googelAuthKey + qr_create_prefix_url: https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=otpauth://totp/%s@%s?secret=%s + +#敦煌api 请求参数 +dh: + access_token: 0QkUo9opYCcmB0UMzqK2XKFFNDDvlpmpRYyDkcVJ + buy_order_url: http://api.dhgate.com/dop/router + buy_order_method: dh.buyer.order.place + buy_order_v: 2.0 + pay_order_url: http://api.dhgate.com/dop/router + pay_order_method: dh.buyer.order.pay + pay_order_v: 1.0 \ No newline at end of file diff --git a/wjcy-system/src/main/resources/config/application-xxs.yml b/wjcy-system/src/main/resources/config/application-xxs.yml new file mode 100644 index 0000000..7471b8b --- /dev/null +++ b/wjcy-system/src/main/resources/config/application-xxs.yml @@ -0,0 +1,417 @@ +#配置数据源 +spring: + datasource: + druid: + db-type: com.alibaba.druid.pool.DruidDataSource + driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy + url: jdbc:log4jdbc:mysql://120.77.145.59:3306/jlt_capiltal?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false + username: root + password: 416909 + # 初始连接数 + initial-size: 5 + # 最小连接数 + min-idle: 15 + # 最大连接数 + max-active: 30 + # 超时时间(以秒数为单位) + remove-abandoned-timeout: 180 + # 获取连接超时时间 + max-wait: 3000 + # 连接有效性检测时间 + time-between-eviction-runs-millis: 60000 + # 连接在池中最小生存的时间 + min-evictable-idle-time-millis: 300000 + # 连接在池中最大生存的时间 + max-evictable-idle-time-millis: 900000 + # 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除 + test-while-idle: true + # 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个 + test-on-borrow: true + # 是否在归还到池中前进行检验 + test-on-return: false + # 检测连接是否有效 + validation-query: select 1 + # 配置监控统计 + webStatFilter: + enabled: true + stat-view-servlet: + enabled: true + url-pattern: /druid/* + reset-enable: false + filter: + stat: + enabled: true + # 记录慢SQL + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + config: + multi-statement-allow: true + slf4j: + enabled: true + statement-create-after-log-enabled: false + statement-close-after-log-enabled: false + result-set-open-after-log-enabled: false + result-set-close-after-log-enabled: false + result-set-next-after-log-enabled: false + + redis: + #数据库索引 + database: 12 + host: 120.77.145.59 + port: 6379 + password: 416909 + #连接超时时间 + timeout: 5000 + #过期时间 1个月(60*60*24*30) + expired: 2592000 + + mvc: + view: + prefix: classpath:/templates/ + suffix: .html + thymeleaf: + cache: false + + +logging: + config: classpath:log4j2.xml + level: + me.zhengjie: debug + +#Mybatis plus 配置 +mybatis-plus: + # 映射文件所在路径 + mapper-locations: classpath*:me/zhengjie/dao/mapper/*.xml + # pojo类所在包路径 + #typeAliasesPackage: + # 开启驼峰命名规则自动转换 + configuration: + map-underscore-to-camel-case: true + log-impl: org.apache.ibatis.logging.log4j2.Log4j2Impl + global-config: + db-config: + # 配置表明前缀,例如表设计时表名为tb_manager,对应entity为Manager + #table-prefix: tb_ + #逻辑已删除值 + logic-delete-value: 1 + #逻辑未删除值 + logic-not-delete-value: 0 + # 是否开启like查询,即对 stirng 字段是否使用 like,默认不开启 + column-like: true + +# 登录相关配置 +login: + # 登录缓存 + cache-enable: true + # 是否限制单用户登录 + single-login: false + # 验证码 + login-code: + # 验证码类型配置 查看 LoginProperties 类 + code-type: arithmetic + # 登录图形验证码有效时间/分钟 + expiration: 2 + # 验证码高度 + width: 111 + # 验证码宽度 + height: 36 + # 内容长度 + length: 2 + # 字体名称,为空则使用默认字体 + font-name: + # 字体大小 + font-size: 25 + +#jwt +jwt: + header: Authorization + # 令牌前缀 + token-start-with: Bearer + # 必须使用最少88位的Base64对该令牌进行编码 + base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI= + # 令牌过期时间 此处单位/毫秒 ,默认4小时,可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html + token-validity-in-seconds: 14400000 + # 在线用户key + online-key: online-token- + # 验证码 + code-key: code-key- + # token 续期检查时间范围(默认30分钟,单位毫秒),在token即将过期的一段时间内用户操作了,则给用户的token续期 + detect: 1800000 + # 续期时间范围,默认1小时,单位毫秒 + renew: 3600000 + +#是否允许生成代码,生产环境设置为false +generator: + enabled: true + +#是否开启 swagger-ui +swagger: + enabled: true + +# IP 本地解析 +ip: + local-parsing: true + +# 文件存储路径 +file: + mac: + path: ~/file/ + avatar: ~/avatar/ + linux: + path: /home/luckyDraw/file/ + avatar: /home/luckyDraw/avatar/ + windows: + path: C:\luckyDraw\file\ + avatar: C:\luckyDraw\avatar\ + # 文件大小 /M + maxSize: 100 + avatarMaxSize: 5 + + +system: + imgPath: /home/waguda/capiltal/file/ + # 静态资源访问路径(返回前端时添加) + fileVisitAddr: http://img.com + #文件上传接口后缀,用来放行xss过滤 + uploadSuffix: file/uploadFile + # 单文件上传大小限制,单位 :MB + maxFileSize: 10 + # 视频单文件上传限制,单位 :MB + maxVideoFileSize: 25 + # ip库文件的绝对路径 window 就是指到resource下的ip2region下 + ip2regionDbPath: /home/work/services/capiltal/capiltal-system/ip2region/ip2region.db + # 多语言文件路径 + languagePath: /home/waguda/capiltal/language + wsUrl: ws://192.168.110.99:8110 + # 百度翻译 APPID + baiduAppId: 20211116001000718 + # 百度翻译privateKey + baiduPrivateKey: jSDxw0_QkRnbRdRT0rKY + +config: + # 放掉的api 校验token huijia@biying123 - https://md5jiami.51240.com/ + apiToken: "e6f5e41ca6b103070ff89c812a36eaec" + #文件上传前缀(首位+'/' 末尾不加'/'),用来放行静态资源访问权限(图片,音频等) + uploadPrefix: /capital + # 图片上传保存路径(注意格式,首尾带‘/’) key:图片上传类型 value: + uploadImgPath: + # 用户头像修改 + 1: /capital/img/ + 2: /capital/rotation/ + 3: /capital/article/ + 4: /capital/currency/ + # 提现审核提示音 + 5: /capital/tones/ + # 聊天室默认头像 + 6: /capital/chat/head/ + # 聊天室会员上传的图片 + 7: /capital/chat/img/ + # 聊天室会员上传视频 + 8: /capital/chat/video/ + 9: /capital/promotion/ + # 平台UBB 富文本 + 10: /capital/platUBB/ + # 支持文件上传的文件格式 + sustainImgFormat: + - img + - jpg + - png + - mp3 + - pem + - jpeg + - gif + - JPG + - JPEG + - PNG + - AVI + - mov + - rmvb + - rm + - FLV + - mp4 + - 3GP + - zip + +web3j: + # web3j 区块链信息 + linkAddress: + #火币 + - name: HECO + # 服务实现类全限定类名 + serverName: "me.zhengjie.web3j.service.impl.ETHBlockchainServiceImpl" + # rpc 连接地址 + url: https://http-testnet.hecochain.com + # 官网域名+查询交易明细 + domain: https://testnet.hecoinfo.com/tx + # 链路Id,必须以 0x开头 + chainId: "0x100" + #合约币种 + contracts: + USDT: + address: "0x425a2d7c3df8a7872f05405dc6e34b6d9cd714be" + accuracy: 18 + MDX: + address: "0x30e552B5Ce0495A55b9138343dD88d6457a6C66b" + accuracy: 18 + DMT: + address: "0x4da2F416aa79fB0BeCA3D6cf6EB6Fe86b4a747CF" + accuracy: 18 + + # ok链 + - name: OKEX + # 服务实现类全限定类名 + serverName: "me.zhengjie.web3j.service.impl.ETHBlockchainServiceImpl" + # rpc 连接地址 + url: https://exchaintestrpc.okex.org + # 官网域名+查询交易明细 + domain: https://www.oklink.com/zh-cn/oec-test/tx + # 链路Id,必须以 0x开头 + chainId: "0x41" + #合约币种 + contracts: + USDT: + address: "0x1328bB18fe06647878d04fcB94BA5474c85C7616" + accuracy: 18 + MDX: + address: "" + accuracy: 0 + DMT: + address: "" + accuracy: 0 + + # 币安链 + - name: BSC + # 服务实现类全限定类名 + serverName: "me.zhengjie.web3j.service.impl.ETHBlockchainServiceImpl" + # rpc 连接地址 https://data-seed-prebsc-1-s1.binance.org:8545/ https://data-seed-prebsc-2-s3.binance.org:8545 + url: https://data-seed-prebsc-1-s1.binance.org:8545/ + # 官网域名+查询交易明细 + domain: https://testnet.bscscan.com/tx + # 链路Id,必须以 0x开头 + chainId: "0x61" + #合约币种 + contracts: + USDT: + # address: "0x3D39e763d2942816c96E783bb53C7c5DB44AFFF3" + address: "0xA12327AaE5C6CCcf816bAC49136f050FeFe89CB6" + accuracy: 18 + MDX: + address: "0x79CA70F863c4273Bb276F37381e1aD2096b77CeE" + accuracy: 18 + ETH: + address: "0x19E6689Bb9CF7Ef04AFf57B77562E4C943c415cD" + accuracy: 18 + CAKE: + address: "0xeBb3CD5EF4a5875AEfcf02CeAaa77Ac8A164523f" + accuracy: 18 + + # 波场 + - name: TRON + # 服务实现类全限定类名 + serverName: "me.zhengjie.web3j.service.impl.TronBlockchainServiceImpl" + # rpc 连接地址, 可选: mainnet、shasta、nile,或其他节点(例:47.252.19.181) + network: shasta + # http接口请求的URL + url: https://api.shasta.trongrid.io + # 官网域名+查询交易明细 + domain: https://shasta.tronscan.org//#/transaction + # 私钥,波场调用API时,不管什么接口都必须要设置私钥 + hexPrivateKey: "780e0d9997862dfac8e0698c8dd457531c9c13ecf6cec377315e95c30b43c8c4" + # 说明:https://cn.developers.tron.network/reference/%E4%BB%80%E4%B9%88%E6%98%AFapi-key e3506c97-a4b6-4bf7-829a-6a5d48b112f7 + apiKey: "" + #合约币种 + contracts: + USDT: + # TNuoKL1ni8aoshfFL1ASca1Gou9RXwAzfn USDT:TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf + address: "TNpzntv25qsy1HVWQW2jCrhWj5wad3tVcj" + accuracy: 10 + MDX: + address: "" + accuracy: 0 + DMT: + address: "" + accuracy: 0 + + blockchain: + 1: + - currencyType: 1 + name: USDT + - currencyType: 2 + name: MDX + - currencyType: 3 + name: DMT + 2: + - currencyType: 1 + name: USDT + 4: + - currencyType: 1 + name: USDT + - currencyType: 2 + name: MDX + - currencyType: 5 + name: ETH + - currencyType: 4 + name: CAKE + 5: + - currencyType: 1 + name: USDT + +# 采集开奖结果配置 +draw: + config: + configs: + - passType: 1 #链路 火币链 + currency: BTC #采集币种 BTC + url: https://api.huobi.pro/market/history/kline #采集地址 + period: 1min #采集周期 1min, 5min, 15min, 30min, ---- 60min, 4hour, 1day, 1mon, 1week, 1year + symbol: btcusdt #交易对 btcusdt, ethbtc + size: 120 #返回数据条数 1 - 2000 + - passType: 4 #链路 币安链 + currency: BTC #采集币种 BTC + url: https://api.binance.com/api/v3/klines #采集地址 + period: 1m #采集周期 #采集周期 1m, 3m, 5m, 15m, 30m, ---- 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M + symbol: BTCUSDT #交易对 + size: 120 #返回数据条数 1 - 1000 + +#该应用是否启用生产者 +rocketmq: + producer: + isOnOff: on + #发送同一类消息的设置为同一个group,保证唯一,默认不需要设置,rocketmq会使用ip@pid(pid代表jvm名字)作为唯一标示 + groupName: springboot-rocketmq-producer-capiltal + #mq的nameserver地址 + namesrvAddr: 120.77.145.59:9876 + #消息最大长度 默认1024*4(4M) + maxMessageSize: 4096 + #发送消息超时时间,默认3000 + sendMsgTimeout: 3000 + #发送消息失败重试次数,默认2 + retryTimesWhenSendFailed: 2 + consumer: + isOnOff: on + groupName: springboot-rocketmq-consumer-capiltal + #mq的nameserver地址 43.240.95.168 + namesrvAddr: 120.77.145.59:9876 + #该消费者订阅的主题和tags("*"号表示订阅该主题下所有的tags),格式:topic~tag1||tag2||tag3;topic2~*; + topics: capiltal-settlement-top~* + consumeThreadMin: 20 + consumeThreadMax: 64 + #设置一次消费消息的条数,默认为1条 + consumeMessageBatchMaxSize: 1 + +# Goole Auth +auth: + secret_size: 10 + seed: g8GjEvTbW5oVSV7avLBdwIHqGlUYNzKFI7izOF8GwLDVKs2m0QN7vxRs2im5MDaNCWGmcD2rvcZx + random_number_algorithm: SHA1PRNG + window_size: 0 + redis_google_auth_key: googelAuthKey + qr_create_prefix_url: https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=otpauth://totp/%s@%s?secret=%s + +#telegram: +# bot: +# username: capiltal_uat_bot +# token: 5008414161:AAHflrbo2v0DN8hpLhZAg5gC787yxFloWlk +# chatId: -665412272 \ No newline at end of file diff --git a/wjcy-system/src/main/resources/config/application.yml b/wjcy-system/src/main/resources/config/application.yml new file mode 100644 index 0000000..bf5a2ad --- /dev/null +++ b/wjcy-system/src/main/resources/config/application.yml @@ -0,0 +1,56 @@ +server: + port: 8008 + +spring: + cache: + type: redis + freemarker: + check-template-location: false + profiles: + active: dev + jackson: + time-zone: GMT+8 + data: + redis: + repositories: + enabled: false + + #配置 Jpa + jpa: + properties: + hibernate: + ddl-auto: none + dialect: org.hibernate.dialect.MySQL5InnoDBDialect + open-in-view: true + +# 开启security功能,配置访问账号密码 +management: + security: + enabled: true +security: + username: admin + userpassword: capiltal&xxs&123 + +task: + pool: + # 核心线程池大小 + core-pool-size: 10 + # 最大线程数 + max-pool-size: 30 + # 活跃时间 + keep-alive-seconds: 60 + # 队列容量 + queue-capacity: 50 + +#七牛云 +qiniu: + # 文件大小 /M + max-size: 15 + +#邮箱验证码有效时间/秒 +code: + expiration: 300 + +#密码加密传输,前端公钥加密,后端私钥解密 +rsa: + private_key: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A== diff --git a/wjcy-system/src/main/resources/generator.properties b/wjcy-system/src/main/resources/generator.properties new file mode 100644 index 0000000..2ed9370 --- /dev/null +++ b/wjcy-system/src/main/resources/generator.properties @@ -0,0 +1,27 @@ +#数据库类型转Java类型 +tinyint=Integer +smallint=Integer +mediumint=Integer +int=Integer +integer=Integer + +bigint=Long + +float=Float + +double=Double + +decimal=BigDecimal + +bit=Boolean + +char=String +varchar=String +tinytext=String +text=String +mediumtext=String +longtext=String + +date=Timestamp +datetime=Timestamp +timestamp=Timestamp \ No newline at end of file diff --git a/wjcy-system/src/main/resources/ip2region/ip2region.db b/wjcy-system/src/main/resources/ip2region/ip2region.db new file mode 100644 index 0000000000000000000000000000000000000000..43e1daf59a7bf34977adc6be925e5ea0d4a2cd22 GIT binary patch literal 6502265 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�ZN#(; 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

C^1@uO@)hd^>{0T4!hQQQK>{Yzv8p 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


_HHoRuj76gEAgH-a(cO`?q5PQoL;THC9}>5j*PH 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�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

_rNo4EzN@O)%Lp|vA>Y) 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

bfuHw;=s@#(B@U{;3*O!8>4Ag# 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

)Y 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%0Dwy@V8GUL#0h$LX}r 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%0AWqzSoOf~J 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 z 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
$vyv2b%B0gn50} zj|X(N==e0c8`>_4!_xOyK58wW_7Y z{wfa_JZziKcNO9)tzV6wde}Cfse2mNJZziKs@38HTIV2sR@-?FH)#8f_?qUg;~~ut z;}Ok|Vn_FDJ%S&Rd9ecYKVX~B_<3-0z&?04&p9bLRr8B+TEISihVe|tSpoao#nf4Y zZ`b;F;JdVbZom!@Zk-@yh;Z8vQ#yocKM(u0oo%>Cw=KqmY5za)PR;MaWx8!S-mCrD zho92?)A+x&{{P?u+Rj0IIAE8ZrT<58gVt}vztsA_!mn%oH2y!`whdpsUX+Kay>&y}bXhSL#II zw7s%zI`;0Befe;S)+xmg?UjA)#(}-|ir4u}U=TaHt+kJB_t_mk<9zqwz&`oAa}d|< zlVhyMP2}Cr9yH^S)(>OCoKvr2!u&n`HSB2K`Z4YQ*f#%9%7<%yEcI(~=*Ln&j2*3G z?dScF{W8w6IBCCazI)}tY5Q&S{j7BC-7kOV_2Jz8@;BT(yk)=qZFegs%x_kF2N!6* z5SQ$izr~m0zg1= zw)u^MUOcehc7H>|8pO_i+x;JBmQ}?uR+-myRxD1cvd!-mcyL;kyzi8by;U;)KAc-+ zyZ`UZ%B!-+5UmAcZXHYMhWo$F#!)&OC2wuQcT3(Xz=T`hD#XOByO`_m;*u)4kCfs- zl^jbDS5?_>7L8eKRpYuU8Hak@R3(2CZ^of28MiR*s50+US)I72%HHq(&#zuQP-UKt ztwHQm+4=3`R#;Xwu9m#@6OQpG_J8ww-11@Pr}kWaqsFqHqCfv5`QZOhr^XKDllRqd zEH$?I4VFS&r}=u^r1@s-Xx^%|qX_HkV^X6jlg8AVHa(Q{3HNth7EmT@K7}%saO*Fo zTplU)S5WRG+~$m7f_}W?zW35(}?tMj9Hpa={Wx@ z$7mg3Jsgl@jKygOk$1sB!qnM<3GtqaV zOqlDr9~0(#%G>b0TE7VYr`F$&2~%eWCd?e&hY2$;_hZ7;DZzxPQ;K)i$$Hp@19kG* zq#&-UGq3%vYFtw%=UpwX)B5$esm|WtilB7bp0(ZI-Ll%TBYDeuj(LC1{Qbi6;J|a*4h}sh_uMdco|87M!{iUk ze#3a+uxi_o278alzI^z;Bhu#m zN9@q!Qa?WJK zd)&H4nHNfjF!SQYg!vnm4~H6c9a`X#x00LztZ~%b~JAtrOr`l zGkDbY68@4gDL%>&G4Wfxk4@=R9JSrwK(i|G-lNj~K3t{w>Z5jU%~3P{d6XT5JN})N zj^?ded_cE7h@UwseLI8+v$pFnVb)1K4jq;84C6NXJw&+mhbiNFj+$#uJf%aJ=aybPpzRFe>-5L{AFThxgqiDq;gO>< z{-fB@ZLMQmGmpu2EEXpnld;l65>}4UP zv-6l7<1YLIZU3QTcE`h#@1zVpBKa_-6VUoWOql;2{3s^OF+PR~Gd_=F!qnM=e|Svp z?@wUDd{3bQ6Xuz}5?39QajwQcJ!aO7^%N%DHDf(}%uYId%yz#k=b>~6lRtt9ca2#; zKV}DhA^9MsL&$gTIQ9mqQ%D&g+Xvoe=fiwHL;Y*0-K#uAi6jjKy)!%X*H->oo7hgxRkT z2cFk+90#A5em;r`b6!7&AAerf{~k=Z?=4$D#DuBy1SZV!R^Y1VrT^9VpziA#OqjVo zgzGe4kNY&=j|ZNY;~K;tYdfD{=XsfT>jm2(O#jE=i7!Z-lQ3cOF_ihaQjOnJeq zr68q4m~(k5Cd?X}h6yv~(=lP*&zXT|z98#-7EX9U`j&{3XvaMVJ=pt#-V1Q<3$m8- z*e~JEX^^sD;|pfZ6jFu=cfExvlQv1-LmBvYtxxF?X6=2Ge7@8VQicdOAEtB&vt~Bq z0zIxm{M{Gqy(K&Y+c=>858|X|86QtG&sWVdKG(6MdFw^$zbNw<#LkN{zt&5vx0m$V zjyqnGG3>-WFUgqnV#197d-&Q*+CCm4@7~9U@rbrF`jQ<*xa%jH(s8tob)0@4mvh;J zy~kyoeK>er`tT^OI4*swJZ^^wGbWTtPaZd8;-T~s=H5Z+R7oAH`nWxTaId$Klu?9x zO^c>%+ON(w{uMu~q7C!uhSTug$oiRi3E|aX_~X;*iz}c<@|pe;&@1`qnD!)w~Y}$h+6EAg(ti(SPm|<(DILNbS2J$WHe2!U=!1J-eg%g#AI7ih_`HS*a}K_a33IJJjoY+- zJMMT{=CKopPD($+Cs~IlifD+x#9T%=x<$6Xv*f;j&Y5T;({Rb%K~MYwuC~nAU$B z6Q-YgaFzD68b77mK8^qTl#Jp3V8ZOH1|QIV9>mX_lDRvC>tr0PdK}_--QO_|<5#KU zuD#bVVUF>2Oqe-3joY;U?U*p%Q+@-V)4rX@UAk>ICd~M}jo;BeT)>3MU&MdaV|f=3 zXdedg&?#Bl!+1pZJBkU@&(ASoo(;ah4*hiRYu4|0Kj9S_hqPB%8?VS*q+{gAK`&lWQ`4CN87YQwlgLq<2Du(W^Bjd2_flQB)%~uV|5dr6q2!u32{A? ze2~&1%=3IK&JIc6a`1X>X9LdFd>+mZ$vAArTeJ^bF=3A7JD4zQ@@`C+aVx-qkj!Hc zSA^uaDluW|Jc+B=m%GlZaf7zmh>vQ2j^XFEofj}+j=c#JW?q_cNb7`goA$FEcW9fP zxJ&DI;|p5nA|_0mf5n8k_P&dIw4c4WPwV&NYue6rJfwAo@rc$L#g2}N6=sgYcI21% z40a?=3d{F6JUF2FAg&18FJ$q(p-Nm6mhXeq;yTUO<4{<>rxV7nhvjqWr!ir^OZ9vF z$FO{7>QDHR<}c&FY5oIDnD1NlVZvx4^;Z^x; zc_RM$tMXa&yKt`N^YAxbmCvRB8{VjOHsKKy-;4Xs$amlR@fEFe6+2qTI?HwAtbE5O7EeDbYi0&cIcvYL zV$3S*7EGA6vmp(<%Lr>|`!F<@~zX}S%1WTls;I0!he$b z);Y%ToUG49IQ5*Y=fyZp^XYi`Ia$vuaE8{ poA!{0h5=lHkr&T}$WyD(wCQ~3ZU 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
p+qarmFOlz9 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 #-BH_eyuy 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