From e231c1b1e095e27d62a5a5252909b2ea9937f6ca Mon Sep 17 00:00:00 2001 From: chaoneng Date: Mon, 23 Jul 2018 21:36:56 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 21 ++ README.md | 57 ++++ fumao-app/pom.xml | 62 +++++ .../java/com/chilunyc/fumao/Application.java | 48 ++++ .../api/company/CompanyAdminController.java | 104 +++++++ .../fumao/api/company/FindPwdController.java | 54 ++++ .../api/company/LoginLogoutController.java | 54 ++++ .../api/company/PlaceAdminController.java | 91 +++++++ .../fumao/api/company/PlaceController.java | 87 ++++++ .../api/company/ShopApplyController.java | 44 +++ .../fumao/api/customer/WxMaController.java | 81 ++++++ .../api/market/LoginLogoutController.java | 49 ++++ .../fumao/api/merchant/WxMaController.java | 81 ++++++ .../api/system/CompanyAdminController.java | 86 ++++++ .../fumao/api/system/CompanyController.java | 86 ++++++ .../fumao/api/system/FindPwdController.java | 54 ++++ .../fumao/api/system/LBSController.java | 42 +++ .../api/system/LoginLogoutController.java | 52 ++++ .../api/system/PlaceAdminController.java | 79 ++++++ .../fumao/api/system/PlaceController.java | 86 ++++++ .../api/system/PlaceFloorController.java | 78 ++++++ .../fumao/api/system/ShopApplyController.java | 65 +++++ .../api/system/SystemAdminController.java | 77 ++++++ .../config/bean/MultiBeanNameGenerator.java | 21 ++ .../fumao/config/captcha/CaptchaConfig.java | 32 +++ .../fumao/config/swagger/SwaggerConfig.java | 76 ++++++ .../chilunyc/fumao/config/web/JsonConfig.java | 21 ++ .../chilunyc/fumao/config/web/WebConfig.java | 78 ++++++ .../fumao/config/web/WebSecurityConfig.java | 58 ++++ .../web/arguments/DateArgumentResolver.java | 38 +++ .../arguments/LoginUserArgumentResolver.java | 34 +++ .../web/interceptor/AuthInterceptor.java | 36 +++ .../web/interceptor/CorsInterceptor.java | 54 ++++ .../web/security/SecurityEntryPoint.java | 26 ++ .../config/web/security/SecurityFilter.java | 141 ++++++++++ .../fumao/controller/FindPwdController.java | 62 +++++ .../controller/common/CaptchaController.java | 58 ++++ .../controller/common/LogController.java | 43 +++ .../controller/common/UploadController.java | 34 +++ .../controller/error/ExceptionController.java | 177 ++++++++++++ .../controller/error/PanicController.java | 44 +++ .../resources/application.prod.properties | 111 ++++++++ .../src/main/resources/application.properties | 99 +++++++ fumao-app/src/main/resources/banner.txt | 17 ++ fumao-app/src/main/resources/config.json | 3 + .../src/main/resources/messages.properties | 13 + fumao-app/src/main/resources/permission.json | 8 + fumao-app/src/main/resources/sms.key | 13 + fumao-common/pom.xml | 243 +++++++++++++++++ .../chilunyc/fumao/common/aop/BaseAop.java | 49 ++++ .../fumao/common/aop/cache/CacheAop.java | 130 +++++++++ .../fumao/common/aop/cache/CacheEvict.java | 19 ++ .../fumao/common/aop/cache/Cacheable.java | 24 ++ .../fumao/common/aop/limit/Limit.java | 23 ++ .../fumao/common/aop/limit/LimitAop.java | 41 +++ .../chilunyc/fumao/common/aop/lock/Lock.java | 23 ++ .../fumao/common/aop/lock/LockAop.java | 38 +++ .../fumao/common/aop/retry/Retry.java | 22 ++ .../fumao/common/aop/retry/RetryAop.java | 32 +++ .../common/config/ApplicationProperty.java | 24 ++ .../fumao/common/config/CacheEnums.java | 9 + .../fumao/common/config/ConfigEnum.java | 8 + .../fumao/common/config/ConfigRequest.java | 14 + .../fumao/common/config/ConfigService.java | 46 ++++ .../fumao/common/config/RedissonConfig.java | 23 ++ .../fumao/common/context/LoginUser.java | 42 +++ .../fumao/common/context/Request.java | 77 ++++++ .../fumao/common/context/RequestHolder.java | 20 ++ .../fumao/common/enums/Comparing.java | 10 + .../chilunyc/fumao/common/enums/YesOrNo.java | 10 + .../common/exception/SystemException.java | 48 ++++ .../fumao/common/lbs/config/LBSConfig.java | 12 + .../common/lbs/config/LBSProperties.java | 14 + .../fumao/common/lbs/model/LBSAddress.java | 20 ++ .../fumao/common/lbs/model/LBSPoi.java | 42 +++ .../common/lbs/request/LBSPoiRequest.java | 15 ++ .../fumao/common/lbs/service/LBSService.java | 78 ++++++ .../fumao/common/log/model/Event.java | 64 +++++ .../fumao/common/log/model/EventTarget.java | 8 + .../fumao/common/log/model/EventType.java | 12 + .../common/log/repository/EventMapper.java | 16 ++ .../log/repository/EventRepository.java | 12 + .../common/log/request/LogPageRequest.java | 21 ++ .../common/log/response/LogResponse.java | 24 ++ .../common/log/service/EventService.java | 77 ++++++ .../fumao/common/request/AssignsRequest.java | 20 ++ .../common/request/ChangePwdRequest.java | 15 ++ .../fumao/common/request/IdsRequest.java | 23 ++ .../fumao/common/request/LoginRequest.java | 24 ++ .../request/LoginRequestWithCaptcha.java | 21 ++ .../common/request/LoginRequestWithSMS.java | 19 ++ .../fumao/common/request/PageRequest.java | 45 ++++ .../fumao/common/response/JsonResponse.java | 78 ++++++ .../fumao/common/response/KeyValue.java | 15 ++ .../fumao/common/response/KeyValues.java | 18 ++ .../fumao/common/response/NodeResponse.java | 24 ++ .../fumao/common/shiro/AuthRoles.java | 25 ++ .../chilunyc/fumao/common/shiro/AuthUser.java | 72 +++++ .../fumao/common/sms/config/SmsConfig.java | 17 ++ .../common/sms/config/SmsProperties.java | 37 +++ .../chilunyc/fumao/common/sms/model/Sms.java | 69 +++++ .../fumao/common/sms/model/SmsType.java | 27 ++ .../common/sms/repository/SmsRepository.java | 38 +++ .../common/sms/request/SmsCheckRequest.java | 40 +++ .../common/sms/request/SmsSendRequest.java | 34 +++ .../fumao/common/sms/service/SmsService.java | 116 ++++++++ .../common/upload/config/UploadConfig.java | 30 +++ .../upload/config/UploadProperties.java | 25 ++ .../common/upload/request/UploadRequest.java | 16 ++ .../upload/response/UploadResponse.java | 30 +++ .../common/upload/service/UploadService.java | 59 ++++ .../fumao/common/util/BeanHelper.java | 45 ++++ .../fumao/common/util/CountHelper.java | 77 ++++++ .../fumao/common/util/CovertHelper.java | 54 ++++ .../fumao/common/util/CryptoHelper.java | 50 ++++ .../fumao/common/util/DateHelper.java | 28 ++ .../fumao/common/util/DateRangeHelper.java | 116 ++++++++ .../fumao/common/util/MapBuilder.java | 25 ++ .../fumao/common/util/MathHelper.java | 17 ++ .../fumao/common/util/SpelHelper.java | 37 +++ .../fumao/common/util/SpringHelper.java | 24 ++ .../fumao/common/util/StreamHelper.java | 40 +++ .../util/excel/ExcelEntityDescription.java | 106 ++++++++ .../excel/ExcelEntityFieldDescription.java | 30 +++ .../fumao/common/util/excel/ExcelHelper.java | 78 ++++++ .../common/util/excel/column/ExcelColumn.java | 26 ++ .../util/excel/column/ExcelColumnReader.java | 21 ++ .../util/excel/column/ExcelColumnWriter.java | 14 + .../impl/DefaultExcelColumnReaderWriter.java | 105 ++++++++ .../fumao/common/util/excel/row/ExcelRow.java | 18 ++ .../common/util/excel/row/ExcelRowReader.java | 7 + .../common/util/excel/row/ExcelRowWriter.java | 7 + .../common/util/http/config/HttpConfig.java | 34 +++ .../common/util/http/config/HttpProperty.java | 18 ++ .../common/util/http/service/HttpClient.java | 36 +++ .../util/http/service/HttpException.java | 51 ++++ .../util/http/service/HttpMulitiParam.java | 25 ++ .../common/util/http/service/HttpParams.java | 255 ++++++++++++++++++ .../common/util/http/service/UrlBuilder.java | 40 +++ .../service/result/ByteResultExecute.java | 25 ++ .../result/JsonArrayResultExecute.java | 28 ++ .../result/JsonObjectResultExecute.java | 27 ++ .../http/service/result/ResultExecute.java | 16 ++ .../service/result/StringResultExecute.java | 25 ++ .../util/jpa/CustomIdentifierGenerator.java | 55 ++++ .../util/jpa/coverter/AesConverter.java | 45 ++++ .../util/jpa/coverter/JsonConverter.java | 24 ++ .../jpa/generator/SnowflaskGenerator.java | 130 +++++++++ .../common/util/jpa/query/QueryBuilder.java | 157 +++++++++++ .../common/util/jpa/query/QueryItem.java | 42 +++ .../common/util/jpa/query/QueryType.java | 40 +++ .../fumao/common/util/jpa/query/SortItem.java | 27 ++ .../common/util/jpa/query/SortItems.java | 16 ++ .../fumao/common/util/jwt/JwtUtils.java | 85 ++++++ .../fumao/common/util/jwt/JwtValue.java | 24 ++ .../common/util/security/SaltHelper.java | 40 +++ .../fumao/common/util/valid/Captcha.java | 22 ++ .../common/util/valid/CaptchaValidator.java | 27 ++ .../chilunyc/fumao/common/util/valid/Geo.java | 22 ++ .../fumao/common/util/valid/GeoValidator.java | 25 ++ .../weixin/config/WechatConfiguration.java | 47 ++++ .../weixin/config/WechatMaConfiguration.java | 40 +++ .../weixin/config/WechatMaProperties.java | 23 ++ .../weixin/config/WechatMpProperties.java | 46 ++++ .../weixin/request/WxMaUserInfoRequest.java | 20 ++ .../main/lib/aliyun-java-sdk-core-3.2.2.jar | Bin 0 -> 84648 bytes ...liyun-java-sdk-dysmsapi-1.0.0-SANPSHOT.jar | Bin 0 -> 17951 bytes .../fumao/common/log/repository/LogMapper.xml | 36 +++ fumao-company/pom.xml | 22 ++ .../chilunyc/fumao/company/model/Company.java | 105 ++++++++ .../fumao/company/model/CompanyAdmin.java | 119 ++++++++ .../chilunyc/fumao/company/model/Place.java | 157 +++++++++++ .../fumao/company/model/PlaceAdmin.java | 163 +++++++++++ .../company/model/PlaceAdminPermission.java | 53 ++++ .../fumao/company/model/PlaceFloor.java | 89 ++++++ .../fumao/company/model/ShopApply.java | 80 ++++++ .../company/model/enums/PlaceAdminType.java | 10 + .../repository/CompanyAdminRepository.java | 22 ++ .../company/repository/CompanyRepository.java | 12 + .../repository/PlaceAdminRepository.java | 23 ++ .../repository/PlaceAdminRoleRepository.java | 12 + .../repository/PlaceFloorRepository.java | 18 ++ .../company/repository/PlaceRepository.java | 17 ++ .../repository/ShopApplyRepository.java | 12 + .../chilunyc/fumao/company/request/.gitkeep | 0 .../request/company/CompanyEditRequest.java | 52 ++++ .../request/company/CompanyPageRequest.java | 14 + .../companyAdmin/CompanyAdminEditRequest.java | 45 ++++ .../companyAdmin/CompanyAdminPageRequest.java | 22 ++ .../request/place/PlaceEditRequest.java | 76 ++++++ .../request/place/PlacePageRequest.java | 19 ++ .../placeAdmin/PlaceAdminEditRequest.java | 49 ++++ .../placeAdmin/PlaceAdminPageRequest.java | 23 ++ .../placeFloor/PlaceFloorEditRequest.java | 41 +++ .../placeFloor/PlaceFloorPageRequest.java | 20 ++ .../shopApply/ShopApplyEditRequest.java | 44 +++ .../shopApply/ShopApplyPageRequest.java | 11 + .../chilunyc/fumao/company/response/.gitkeep | 0 .../company/service/CompanyAdminService.java | 113 ++++++++ .../fumao/company/service/CompanyService.java | 89 ++++++ .../service/PlaceAdminRoleService.java | 59 ++++ .../company/service/PlaceAdminService.java | 105 ++++++++ .../company/service/PlaceFloorService.java | 76 ++++++ .../fumao/company/service/PlaceService.java | 104 +++++++ .../company/service/ShopApplyService.java | 62 +++++ .../fumao/company/repository/.gitkeep | 0 fumao-service/pom.xml | 32 +++ .../com/chilunyc/fumao/service/model/.gitkeep | 0 .../fumao/service/repository/.gitkeep | 0 .../chilunyc/fumao/service/request/.gitkeep | 0 .../chilunyc/fumao/service/response/.gitkeep | 0 .../chilunyc/fumao/service/service/.gitkeep | 0 .../fumao/service/repository/.gitkeep | 0 fumao-system/pom.xml | 22 ++ .../fumao/system/model/SystemAdmin.java | 88 ++++++ .../repository/SystemAdminRepository.java | 16 ++ .../chilunyc/fumao/system/request/.gitkeep | 0 .../systemAdmin/SystemAdminEditRequest.java | 38 +++ .../systemAdmin/SystemAdminPageRequest.java | 17 ++ .../chilunyc/fumao/system/response/.gitkeep | 0 .../system/service/SystemAdminService.java | 93 +++++++ .../chilunyc/fumao/system/repository/.gitkeep | 0 pom.xml | 106 ++++++++ 223 files changed, 10010 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 fumao-app/pom.xml create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/Application.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/company/CompanyAdminController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/company/FindPwdController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/company/LoginLogoutController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/company/PlaceAdminController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/company/PlaceController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/company/ShopApplyController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/customer/WxMaController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/market/LoginLogoutController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/merchant/WxMaController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/system/CompanyAdminController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/system/CompanyController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/system/FindPwdController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/system/LBSController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/system/LoginLogoutController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/system/PlaceAdminController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/system/PlaceController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/system/PlaceFloorController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/system/ShopApplyController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/api/system/SystemAdminController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/config/bean/MultiBeanNameGenerator.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/config/captcha/CaptchaConfig.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/config/swagger/SwaggerConfig.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/config/web/JsonConfig.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/config/web/WebConfig.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/config/web/WebSecurityConfig.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/config/web/arguments/DateArgumentResolver.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/config/web/arguments/LoginUserArgumentResolver.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/config/web/interceptor/AuthInterceptor.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/config/web/interceptor/CorsInterceptor.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/config/web/security/SecurityEntryPoint.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/config/web/security/SecurityFilter.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/controller/FindPwdController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/controller/common/CaptchaController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/controller/common/LogController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/controller/common/UploadController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/controller/error/ExceptionController.java create mode 100644 fumao-app/src/main/java/com/chilunyc/fumao/controller/error/PanicController.java create mode 100644 fumao-app/src/main/resources/application.prod.properties create mode 100644 fumao-app/src/main/resources/application.properties create mode 100644 fumao-app/src/main/resources/banner.txt create mode 100644 fumao-app/src/main/resources/config.json create mode 100644 fumao-app/src/main/resources/messages.properties create mode 100644 fumao-app/src/main/resources/permission.json create mode 100644 fumao-app/src/main/resources/sms.key create mode 100644 fumao-common/pom.xml create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/aop/BaseAop.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/aop/cache/CacheAop.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/aop/cache/CacheEvict.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/aop/cache/Cacheable.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/aop/limit/Limit.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/aop/limit/LimitAop.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/aop/lock/Lock.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/aop/lock/LockAop.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/aop/retry/Retry.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/aop/retry/RetryAop.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/config/ApplicationProperty.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/config/CacheEnums.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/config/ConfigEnum.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/config/ConfigRequest.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/config/ConfigService.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/config/RedissonConfig.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/context/LoginUser.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/context/Request.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/context/RequestHolder.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/enums/Comparing.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/enums/YesOrNo.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/exception/SystemException.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/config/LBSConfig.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/config/LBSProperties.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/model/LBSAddress.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/model/LBSPoi.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/request/LBSPoiRequest.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/service/LBSService.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/log/model/Event.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/log/model/EventTarget.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/log/model/EventType.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/log/repository/EventMapper.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/log/repository/EventRepository.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/log/request/LogPageRequest.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/log/response/LogResponse.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/log/service/EventService.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/request/AssignsRequest.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/request/ChangePwdRequest.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/request/IdsRequest.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/request/LoginRequest.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/request/LoginRequestWithCaptcha.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/request/LoginRequestWithSMS.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/request/PageRequest.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/response/JsonResponse.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/response/KeyValue.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/response/KeyValues.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/response/NodeResponse.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/shiro/AuthRoles.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/shiro/AuthUser.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/sms/config/SmsConfig.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/sms/config/SmsProperties.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/sms/model/Sms.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/sms/model/SmsType.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/sms/repository/SmsRepository.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/sms/request/SmsCheckRequest.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/sms/request/SmsSendRequest.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/sms/service/SmsService.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/upload/config/UploadConfig.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/upload/config/UploadProperties.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/upload/request/UploadRequest.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/upload/response/UploadResponse.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/upload/service/UploadService.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/BeanHelper.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/CountHelper.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/CovertHelper.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/CryptoHelper.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/DateHelper.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/DateRangeHelper.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/MapBuilder.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/MathHelper.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/SpelHelper.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/SpringHelper.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/StreamHelper.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/ExcelEntityDescription.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/ExcelEntityFieldDescription.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/ExcelHelper.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/column/ExcelColumn.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/column/ExcelColumnReader.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/column/ExcelColumnWriter.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/column/impl/DefaultExcelColumnReaderWriter.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/row/ExcelRow.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/row/ExcelRowReader.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/row/ExcelRowWriter.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/config/HttpConfig.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/config/HttpProperty.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/HttpClient.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/HttpException.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/HttpMulitiParam.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/HttpParams.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/UrlBuilder.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/ByteResultExecute.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/JsonArrayResultExecute.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/JsonObjectResultExecute.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/ResultExecute.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/StringResultExecute.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/CustomIdentifierGenerator.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/coverter/AesConverter.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/coverter/JsonConverter.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/generator/SnowflaskGenerator.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/QueryBuilder.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/QueryItem.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/QueryType.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/SortItem.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/SortItems.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/jwt/JwtUtils.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/jwt/JwtValue.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/security/SaltHelper.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/valid/Captcha.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/valid/CaptchaValidator.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/valid/Geo.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/util/valid/GeoValidator.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/config/WechatConfiguration.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/config/WechatMaConfiguration.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/config/WechatMaProperties.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/config/WechatMpProperties.java create mode 100644 fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/request/WxMaUserInfoRequest.java create mode 100644 fumao-common/src/main/lib/aliyun-java-sdk-core-3.2.2.jar create mode 100644 fumao-common/src/main/lib/aliyun-java-sdk-dysmsapi-1.0.0-SANPSHOT.jar create mode 100644 fumao-common/src/main/resources/com/chilunyc/fumao/common/log/repository/LogMapper.xml create mode 100644 fumao-company/pom.xml create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/model/Company.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/model/CompanyAdmin.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/model/Place.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/model/PlaceAdmin.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/model/PlaceAdminPermission.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/model/PlaceFloor.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/model/ShopApply.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/model/enums/PlaceAdminType.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/repository/CompanyAdminRepository.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/repository/CompanyRepository.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/repository/PlaceAdminRepository.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/repository/PlaceAdminRoleRepository.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/repository/PlaceFloorRepository.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/repository/PlaceRepository.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/repository/ShopApplyRepository.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/request/.gitkeep create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/request/company/CompanyEditRequest.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/request/company/CompanyPageRequest.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/request/companyAdmin/CompanyAdminEditRequest.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/request/companyAdmin/CompanyAdminPageRequest.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/request/place/PlaceEditRequest.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/request/place/PlacePageRequest.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/request/placeAdmin/PlaceAdminEditRequest.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/request/placeAdmin/PlaceAdminPageRequest.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/request/placeFloor/PlaceFloorEditRequest.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/request/placeFloor/PlaceFloorPageRequest.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/request/shopApply/ShopApplyEditRequest.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/request/shopApply/ShopApplyPageRequest.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/response/.gitkeep create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/service/CompanyAdminService.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/service/CompanyService.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/service/PlaceAdminRoleService.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/service/PlaceAdminService.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/service/PlaceFloorService.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/service/PlaceService.java create mode 100644 fumao-company/src/main/java/com/chilunyc/fumao/company/service/ShopApplyService.java create mode 100644 fumao-company/src/main/resources/com/chilunyc/fumao/company/repository/.gitkeep create mode 100644 fumao-service/pom.xml create mode 100644 fumao-service/src/main/java/com/chilunyc/fumao/service/model/.gitkeep create mode 100644 fumao-service/src/main/java/com/chilunyc/fumao/service/repository/.gitkeep create mode 100644 fumao-service/src/main/java/com/chilunyc/fumao/service/request/.gitkeep create mode 100644 fumao-service/src/main/java/com/chilunyc/fumao/service/response/.gitkeep create mode 100644 fumao-service/src/main/java/com/chilunyc/fumao/service/service/.gitkeep create mode 100644 fumao-service/src/main/resources/com/chilunyc/fumao/service/repository/.gitkeep create mode 100644 fumao-system/pom.xml create mode 100644 fumao-system/src/main/java/com/chilunyc/fumao/system/model/SystemAdmin.java create mode 100644 fumao-system/src/main/java/com/chilunyc/fumao/system/repository/SystemAdminRepository.java create mode 100644 fumao-system/src/main/java/com/chilunyc/fumao/system/request/.gitkeep create mode 100644 fumao-system/src/main/java/com/chilunyc/fumao/system/request/systemAdmin/SystemAdminEditRequest.java create mode 100644 fumao-system/src/main/java/com/chilunyc/fumao/system/request/systemAdmin/SystemAdminPageRequest.java create mode 100644 fumao-system/src/main/java/com/chilunyc/fumao/system/response/.gitkeep create mode 100644 fumao-system/src/main/java/com/chilunyc/fumao/system/service/SystemAdminService.java create mode 100644 fumao-system/src/main/resources/com/chilunyc/fumao/system/repository/.gitkeep create mode 100644 pom.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8c78358 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +/.idea/ + +*.iml +target +*/target + +**/rebel.xml +**/.rebel.xml.bak + +doc + +*.log \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..751fb9c --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ + +## 项目结构 + +* fumao-app + * 对外接口和WEB的配置项 +* fumao-common + * 一些常用的工具类 +* fumao-company + * 集团端代码 +* fumao-system + * 系统端代码 +* fumao-service + * controller里面调用, 聚合其他几个模块的代码 + +## jpa相关 + +### 快速查询 +``` +@QueryItem(type = QueryType.Eq) 等等 +用于快速开发查询接口 + +QueryBuilder.build(条件对象) 返回 Predicate 可交给SpringData 查询 +``` + +### 非外键原则 +``` +@Fetch(FetchMode.JOIN) +@ManyToOne() +@JoinColumn(name = "本实体ID", referencedColumnName = "关联ID", insertable = false, updatable = false, foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)) +@NotFound(action=NotFoundAction.IGNORE) +``` + + +## 权限 + +``` +使用spring security +``` + +* 配置项 + * WebSecurityConfig +* 过滤器 + * SecurityFilter +* 注解 + * PreAuthorize(AuthRoles.xxxExp) +* 使用 + * 实现LoginUser接口 + * 调用JwtUtils.encode + * 方法或者类上面加PreAuthorize注解 + * 动态角色实现 AccessDecisionManager 接口 + + +## 集团实例 + +``` +新建集团的时候会手动跑Flyway方法, 创建一个新实例 +``` \ No newline at end of file diff --git a/fumao-app/pom.xml b/fumao-app/pom.xml new file mode 100644 index 0000000..e715627 --- /dev/null +++ b/fumao-app/pom.xml @@ -0,0 +1,62 @@ + + + + fumao + com.aki + 0.0.1-SNAPSHOT + + 4.0.0 + + fumao-app + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + org.springframework.boot + spring-boot-starter-undertow + + + + + + + + + + com.aki + fumao-service + ${project.version} + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + build-info + + + + + true + true + + + + + \ No newline at end of file diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/Application.java b/fumao-app/src/main/java/com/chilunyc/fumao/Application.java new file mode 100644 index 0000000..8731d5b --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/Application.java @@ -0,0 +1,48 @@ +package com.chilunyc.fumao; + +import com.chilunyc.fumao.common.config.ApplicationProperty; +import com.chilunyc.fumao.config.bean.MultiBeanNameGenerator; +import com.alibaba.fastjson.parser.ParserConfig; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.system.ApplicationPidFileWriter; +import org.springframework.boot.web.servlet.ServletComponentScan; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * + */ +@SpringBootApplication() +@EnableAsync +@EnableScheduling +@EnableJpaRepositories +@EnableJpaAuditing +@EnableTransactionManagement +@EnableWebSecurity +@EnableGlobalMethodSecurity( + prePostEnabled = true +) +@ServletComponentScan() +@EnableConfigurationProperties(ApplicationProperty.class) +public class Application { + + public static void main(String[] args) { + // + ParserConfig.getGlobalInstance().setAutoTypeSupport(true); + + // + ConfigurableApplicationContext run = new SpringApplicationBuilder(Application.class) + .addCommandLineProperties(false) + .listeners(new ApplicationPidFileWriter("./app.pid")) + .beanNameGenerator(new MultiBeanNameGenerator()) + .run(args); + } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/company/CompanyAdminController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/company/CompanyAdminController.java new file mode 100644 index 0000000..8c15681 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/company/CompanyAdminController.java @@ -0,0 +1,104 @@ +package com.chilunyc.fumao.api.company; + +import com.chilunyc.fumao.common.exception.SystemException; +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.shiro.AuthRoles; +import com.chilunyc.fumao.company.model.Company; +import com.chilunyc.fumao.company.model.CompanyAdmin; +import com.chilunyc.fumao.company.request.companyAdmin.CompanyAdminEditRequest; +import com.chilunyc.fumao.company.request.companyAdmin.CompanyAdminPageRequest; +import com.chilunyc.fumao.company.service.CompanyAdminService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +/** + * + */ +@Log4j +@Api(description = "集团管理员") +@RestController +@RequestMapping("/company/admin") +@PreAuthorize(AuthRoles.CompanyAdminExp) +class CompanyAdminController { + + @Autowired + CompanyAdminService companyAdminService; + + + @ApiOperation(value = "分页") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "PageRequest") + }) + @RequestMapping(value = "/find", method = RequestMethod.POST) + JsonResponse> page(CompanyAdmin companyAdmin, @RequestBody CompanyAdminPageRequest request) { + request.setCompanyId(companyAdmin.getCompanyId()); + Page page = companyAdminService.page(request); + return JsonResponse.success(page); + } + + @ApiOperation(value = "详情") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/find/{id}", method = RequestMethod.GET) + JsonResponse info(CompanyAdmin companyAdmin, @PathVariable Long id) { + CompanyAdmin companyAdminResponse = companyAdminService.findByCompanyId(id, companyAdmin.getCompanyId()); + return JsonResponse.success(companyAdminResponse); + } + + + @ApiOperation(value = "新增 | 编辑") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "CompanyAdmin") + }) + @RequestMapping(value = "/edit", method = RequestMethod.POST) + JsonResponse edit(CompanyAdmin companyAdmin, @RequestBody @Valid CompanyAdminEditRequest request) { + request.setCompanyId(companyAdmin.getCompanyId()); + companyAdminService.edit(request); + return JsonResponse.success(); + } + + @ApiOperation(value = "删除") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "IdRequest") + }) + @RequestMapping(value = "/delete", method = RequestMethod.POST) + JsonResponse remove(CompanyAdmin companyAdmin, @RequestBody @Valid IdsRequest request) { + if (request.getIds().contains(companyAdmin.getId())){ + throw new SystemException("100001"); + } + companyAdminService.removeByCompanyId(request, companyAdmin.getCompanyId()); + return JsonResponse.success(); + } + + @ApiOperation(value = "重置密码") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/reset/password/{id}", method = RequestMethod.GET) + JsonResponse resetPassword(CompanyAdmin companyAdmin, @PathVariable Long id) { + companyAdminService.resetPassword(id, companyAdmin.getCompanyId()); + log.info(String.format("集团管理员[ %s ]重置密码 => [ %s ]", companyAdmin.getId(), id)); + return JsonResponse.success(); + } + + + @ApiOperation(value = "所有") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/find/all", method = RequestMethod.GET) + JsonResponse> all(CompanyAdminPageRequest request) { + List result = companyAdminService.all(request); + return JsonResponse.success(result); + } + +} \ No newline at end of file diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/company/FindPwdController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/company/FindPwdController.java new file mode 100644 index 0000000..fb606ae --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/company/FindPwdController.java @@ -0,0 +1,54 @@ +package com.chilunyc.fumao.api.company; + +import com.chilunyc.fumao.common.request.ChangePwdRequest; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.sms.model.SmsType; +import com.chilunyc.fumao.common.sms.request.SmsSendRequest; +import com.chilunyc.fumao.common.sms.service.SmsService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.apache.commons.lang3.RandomStringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + +/** + * + */ +@Log4j +@Api(description = "找回密码") +@RestController +@RequestMapping("/company/find/pwd") +class FindPwdController { + + @Autowired + SmsService smsService; + + @ApiOperation(value = "改密码") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "ChangePwdRequest") + }) + @RequestMapping(value = "/", method = RequestMethod.POST) + JsonResponse login(@RequestBody @Valid ChangePwdRequest request) { + return JsonResponse.success(); + } + + @ApiOperation(value = "改密码发短信") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "SmsSendRequest") + }) + @RequestMapping(value = "/send", method = RequestMethod.POST) + JsonResponse login(@RequestBody @Valid SmsSendRequest request) { + request.setContent(RandomStringUtils.randomNumeric(4)); + request.setType(SmsType.CustomerFindPwd); + smsService.send(request); + return JsonResponse.success(); + } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/company/LoginLogoutController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/company/LoginLogoutController.java new file mode 100644 index 0000000..329901f --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/company/LoginLogoutController.java @@ -0,0 +1,54 @@ +package com.chilunyc.fumao.api.company; + +import com.chilunyc.fumao.common.request.LoginRequest; +import com.chilunyc.fumao.common.request.LoginRequestWithCaptcha; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.util.jwt.JwtUtils; +import com.chilunyc.fumao.company.model.CompanyAdmin; +import com.chilunyc.fumao.company.service.CompanyAdminService; +import com.chilunyc.fumao.company.service.CompanyService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + +/** + * + */ +@Log4j +@Api(description = "登录登出") +@RestController +@RequestMapping("/company") +class LoginLogoutController { + + @Autowired + CompanyAdminService companyAdminService; + + @ApiOperation(value = "登录") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "LoginRequest") + }) + @RequestMapping(value = "/login", method = RequestMethod.POST) + JsonResponse login(@RequestBody @Valid LoginRequest request) { + CompanyAdmin companyAdmin = companyAdminService.login(request); + return JsonResponse.success( + JwtUtils.encode(JwtUtils.T.Company, companyAdmin) + ); + } + + @ApiOperation(value = "登出") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/logout", method = RequestMethod.GET) + JsonResponse logout() { + return JsonResponse.success(); + } +} \ No newline at end of file diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/company/PlaceAdminController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/company/PlaceAdminController.java new file mode 100644 index 0000000..39ab1b4 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/company/PlaceAdminController.java @@ -0,0 +1,91 @@ +package com.chilunyc.fumao.api.company; + +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.shiro.AuthRoles; +import com.chilunyc.fumao.company.model.CompanyAdmin; +import com.chilunyc.fumao.company.model.PlaceAdmin; +import com.chilunyc.fumao.company.model.enums.PlaceAdminType; +import com.chilunyc.fumao.company.request.placeAdmin.PlaceAdminEditRequest; +import com.chilunyc.fumao.company.request.placeAdmin.PlaceAdminPageRequest; +import com.chilunyc.fumao.company.service.PlaceAdminService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + * + */ +@Log4j +@Api(description = "商场管理员") +@RestController +@RequestMapping("/company/place/admin") +@PreAuthorize(AuthRoles.CompanyAdminExp) +class PlaceAdminController { + + @Autowired + PlaceAdminService placeAdminService; + + + @ApiOperation(value = "分页") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "PageRequest") + }) + @RequestMapping(value = "/find", method = RequestMethod.POST) + JsonResponse> page(CompanyAdmin companyAdmin, @RequestBody PlaceAdminPageRequest request) { + request.setCompanyId(companyAdmin.getCompanyId()); + Page page = placeAdminService.page(request); + return JsonResponse.success(page); + } + + @ApiOperation(value = "详情") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/find/{id}", method = RequestMethod.GET) + JsonResponse info(@PathVariable Long id) { + PlaceAdmin placeAdminResponse = placeAdminService.find(id); + return JsonResponse.success(placeAdminResponse); + } + + + @ApiOperation(value = "新增 | 编辑") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "PlaceAdmin") + }) + @RequestMapping(value = "/edit", method = RequestMethod.POST) + JsonResponse edit(CompanyAdmin companyAdmin, @RequestBody @Valid PlaceAdminEditRequest request) { + request.setPlaceAdminType(PlaceAdminType.Manager); + request.setCompanyId(companyAdmin.getCompanyId()); + placeAdminService.edit(request); + return JsonResponse.success(); + } + + @ApiOperation(value = "删除") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "IdRequest") + }) + @RequestMapping(value = "/delete", method = RequestMethod.POST) + JsonResponse remove(@RequestBody @Valid IdsRequest request) { + placeAdminService.remove(request); + return JsonResponse.success(); + } + + + @ApiOperation(value = "重置密码") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/reset/password/{id}", method = RequestMethod.GET) + JsonResponse resetPassword(CompanyAdmin companyAdmin, @PathVariable Long id) { + placeAdminService.resetPassword(id, companyAdmin.getCompanyId()); + log.info(String.format("商场管理员[ %s ]重置密码 => [ %s ]", companyAdmin.getId(), id)); + return JsonResponse.success(); + } +} \ No newline at end of file diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/company/PlaceController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/company/PlaceController.java new file mode 100644 index 0000000..12d02d2 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/company/PlaceController.java @@ -0,0 +1,87 @@ +package com.chilunyc.fumao.api.company; + +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.shiro.AuthRoles; +import com.chilunyc.fumao.company.model.Company; +import com.chilunyc.fumao.company.model.CompanyAdmin; +import com.chilunyc.fumao.company.model.Place; +import com.chilunyc.fumao.company.request.place.PlacePageRequest; +import com.chilunyc.fumao.company.service.PlaceService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * + */ +@Log4j +@Api(description = "商场") +@RestController +@RequestMapping("/company/place") +@PreAuthorize(AuthRoles.CompanyAdminExp) +class PlaceController { + + @Autowired + PlaceService placeService; + + + @ApiOperation(value = "分页") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "PageRequest") + }) + @RequestMapping(value = "/find", method = RequestMethod.POST) + JsonResponse> page(CompanyAdmin companyAdmin, @RequestBody PlacePageRequest request) { + request.setCompanyId(companyAdmin.getCompanyId()); + Page page = placeService.page(request); + return JsonResponse.success(page); + } + + @ApiOperation(value = "详情") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/find/{id}", method = RequestMethod.GET) + JsonResponse info(@PathVariable Long id) { + Place placeResponse = placeService.find(id); + return JsonResponse.success(placeResponse); + } + + +// @ApiOperation(value = "新增 | 编辑") +// @ApiImplicitParams({ +// @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "Place") +// }) +// @RequestMapping(value = "/edit", method = RequestMethod.POST) +// JsonResponse edit(@RequestBody @Valid PlaceEditRequest request) { +// marketService.edit(request); +// return JsonResponse.success(); +// } +// +// @ApiOperation(value = "删除") +// @ApiImplicitParams({ +// @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "IdRequest") +// }) +// @RequestMapping(value = "/delete", method = RequestMethod.POST) +// JsonResponse remove(@RequestBody @Valid IdsRequest request) { +// marketService.remove(request); +// return JsonResponse.success(); +// } + + @ApiOperation(value = "所有") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/find/all", method = RequestMethod.GET) + JsonResponse> all(CompanyAdmin companyAdmin, PlacePageRequest request) { + request.setCompanyId(companyAdmin.getCompanyId()); + List result = placeService.all(request); + return JsonResponse.success(result); + } + +} \ No newline at end of file diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/company/ShopApplyController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/company/ShopApplyController.java new file mode 100644 index 0000000..1a42f0b --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/company/ShopApplyController.java @@ -0,0 +1,44 @@ +package com.chilunyc.fumao.api.company; + +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.company.model.ShopApply; +import com.chilunyc.fumao.company.request.shopApply.ShopApplyEditRequest; +import com.chilunyc.fumao.company.request.shopApply.ShopApplyPageRequest; +import com.chilunyc.fumao.company.service.ShopApplyService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + * + */ +@Log4j +@Api(description = "商铺申请") +@RestController +@RequestMapping("/company/shop/apply") +class ShopApplyController { + + @Autowired + ShopApplyService shopApplyService; + + + @ApiOperation(value = "新增 | 编辑") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "ShopApply") + }) + @RequestMapping(value = "/edit", method = RequestMethod.POST) + JsonResponse edit(@RequestBody @Valid ShopApplyEditRequest request) { + shopApplyService.edit(request); + return JsonResponse.success(); + } + + +} \ No newline at end of file diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/customer/WxMaController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/customer/WxMaController.java new file mode 100644 index 0000000..c66f255 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/customer/WxMaController.java @@ -0,0 +1,81 @@ +package com.chilunyc.fumao.api.customer; + +import io.swagger.annotations.Api; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 80347471@qq.com + */ +@Api("小程序接口") +@RestController +@RequestMapping("/customer/wx/ma") +public class WxMaController { + + +// @Autowired +// WxMaService wxMaService; +// +// @Autowired +// StringRedisTemplate redisTemplate; +// +// /** +// * 转换code +// */ +// @RequestMapping(value = "/code", method = RequestMethod.GET) +// public JsonResponse code(String code) throws WxErrorException { +// if (StringUtils.isBlank(code)) { +// return JsonResponse.fail("参数错误"); +// } +// WxMaJscode2SessionResult session = this.wxMaService.getUserService().getSessionInfo(code); +// redisTemplate.boundValueOps(String.format("%s_session", session.getOpenid())).set(session.getSessionKey()); +// return JsonResponse.success( +// MapBuilder +// .builder() +// .put("openId", session.getOpenid()) +// .getMap() +// ); +// } +// +// /** +// * 转换info +// */ +// @RequestMapping(value = "/info", method = RequestMethod.POST) +// public JsonResponse info(@RequestBody @Valid WxMaUserInfoRequest request) throws WxErrorException { +// String sessionKey = redisTemplate.boundValueOps(String.format("%s_session", request.getOpenId())).get(); +// if (StringUtils.isBlank(sessionKey)) { +// throw new SystemException("000008"); +// } +// +// +// // 用户信息校验 +// if (!this.wxMaService.getUserService().checkUserInfo(sessionKey, request.getRawData(), request.getSignature())) { +// return JsonResponse.fail("校验失败"); +// } +// +// // 解密用户信息 +// WxMaUserInfo userInfo = this.wxMaService.getUserService().getUserInfo(sessionKey, request.getEncryptedData(), request.getIv()); +// +// return JsonResponse.success(); +// } +// +// /** +// * 转换number +// */ +// @RequestMapping(value = "/number", method = RequestMethod.POST) +// public JsonResponse number(@RequestBody @Valid WxMaUserInfoRequest request) throws WxErrorException { +// String sessionKey = redisTemplate.boundValueOps(String.format("%s_session", request.getOpenId())).get(); +// if (StringUtils.isBlank(sessionKey)) { +// throw new SystemException("000008"); +// } +// +// // 用户信息校验 +// if (!this.wxMaService.getUserService().checkUserInfo(sessionKey, request.getRawData(), request.getSignature())) { +// return JsonResponse.fail("校验失败"); +// } +// +// // 解密用户信息 +// WxMaPhoneNumberInfo phoneNoInfo = this.wxMaService.getUserService().getPhoneNoInfo(sessionKey, request.getEncryptedData(), request.getIv()); +// return JsonResponse.success(); +// } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/market/LoginLogoutController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/market/LoginLogoutController.java new file mode 100644 index 0000000..396d7a7 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/market/LoginLogoutController.java @@ -0,0 +1,49 @@ +package com.chilunyc.fumao.api.market; + +import com.chilunyc.fumao.common.request.LoginRequest; +import com.chilunyc.fumao.common.request.LoginRequestWithCaptcha; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.company.service.PlaceAdminService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + +/** + * + */ +@Log4j +@Api(description = "登录登出") +@RestController +@RequestMapping("/place") +class LoginLogoutController { + + @Autowired + PlaceAdminService placeAdminService; + + @ApiOperation(value = "登录") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "LoginRequest") + }) + @RequestMapping(value = "/login", method = RequestMethod.POST) + JsonResponse login(@RequestBody @Valid LoginRequest request) { + placeAdminService.login(request); + return null; + } + + @ApiOperation(value = "登出") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/logout", method = RequestMethod.GET) + JsonResponse logout() { + return JsonResponse.success(); + } +} \ No newline at end of file diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/merchant/WxMaController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/merchant/WxMaController.java new file mode 100644 index 0000000..dec8235 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/merchant/WxMaController.java @@ -0,0 +1,81 @@ +package com.chilunyc.fumao.api.merchant; + +import io.swagger.annotations.Api; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 80347471@qq.com + */ +@Api("小程序接口") +@RestController +@RequestMapping("/merchant/wx/ma") +public class WxMaController { + + +// @Autowired +// WxMaService wxMaService; +// +// @Autowired +// StringRedisTemplate redisTemplate; +// +// /** +// * 转换code +// */ +// @RequestMapping(value = "/code", method = RequestMethod.GET) +// public JsonResponse code(String code) throws WxErrorException { +// if (StringUtils.isBlank(code)) { +// return JsonResponse.fail("参数错误"); +// } +// WxMaJscode2SessionResult session = this.wxMaService.getUserService().getSessionInfo(code); +// redisTemplate.boundValueOps(String.format("%s_session", session.getOpenid())).set(session.getSessionKey()); +// return JsonResponse.success( +// MapBuilder +// .builder() +// .put("openId", session.getOpenid()) +// .getMap() +// ); +// } +// +// /** +// * 转换info +// */ +// @RequestMapping(value = "/info", method = RequestMethod.POST) +// public JsonResponse info(@RequestBody @Valid WxMaUserInfoRequest request) throws WxErrorException { +// String sessionKey = redisTemplate.boundValueOps(String.format("%s_session", request.getOpenId())).get(); +// if (StringUtils.isBlank(sessionKey)) { +// throw new SystemException("000008"); +// } +// +// +// // 用户信息校验 +// if (!this.wxMaService.getUserService().checkUserInfo(sessionKey, request.getRawData(), request.getSignature())) { +// return JsonResponse.fail("校验失败"); +// } +// +// // 解密用户信息 +// WxMaUserInfo userInfo = this.wxMaService.getUserService().getUserInfo(sessionKey, request.getEncryptedData(), request.getIv()); +// +// return JsonResponse.success(); +// } +// +// /** +// * 转换number +// */ +// @RequestMapping(value = "/number", method = RequestMethod.POST) +// public JsonResponse number(@RequestBody @Valid WxMaUserInfoRequest request) throws WxErrorException { +// String sessionKey = redisTemplate.boundValueOps(String.format("%s_session", request.getOpenId())).get(); +// if (StringUtils.isBlank(sessionKey)) { +// throw new SystemException("000008"); +// } +// +// // 用户信息校验 +// if (!this.wxMaService.getUserService().checkUserInfo(sessionKey, request.getRawData(), request.getSignature())) { +// return JsonResponse.fail("校验失败"); +// } +// +// // 解密用户信息 +// WxMaPhoneNumberInfo phoneNoInfo = this.wxMaService.getUserService().getPhoneNoInfo(sessionKey, request.getEncryptedData(), request.getIv()); +// return JsonResponse.success(); +// } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/system/CompanyAdminController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/CompanyAdminController.java new file mode 100644 index 0000000..12b7697 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/CompanyAdminController.java @@ -0,0 +1,86 @@ +package com.chilunyc.fumao.api.system; + +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.shiro.AuthRoles; +import com.chilunyc.fumao.company.model.CompanyAdmin; +import com.chilunyc.fumao.company.request.companyAdmin.CompanyAdminEditRequest; +import com.chilunyc.fumao.company.request.companyAdmin.CompanyAdminPageRequest; +import com.chilunyc.fumao.company.service.CompanyAdminService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +/** + * + */ +@Log4j +@Api(description = "集团管理员") +@RestController +@RequestMapping("/system/company/admin") +@PreAuthorize(AuthRoles.SystemAdminExp) +class CompanyAdminController { + + @Autowired + CompanyAdminService companyAdminService; + + + @ApiOperation(value = "分页") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "PageRequest") + }) + @RequestMapping(value = "/find", method = RequestMethod.POST) + JsonResponse> page(@RequestBody CompanyAdminPageRequest request) { + Page page = companyAdminService.page(request); + return JsonResponse.success(page); + } + + @ApiOperation(value = "详情") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/find/{id}", method = RequestMethod.GET) + JsonResponse info(@PathVariable Long id) { + CompanyAdmin companyAdminResponse = companyAdminService.find(id); + return JsonResponse.success(companyAdminResponse); + } + + + @ApiOperation(value = "新增 | 编辑") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "CompanyAdmin") + }) + @RequestMapping(value = "/edit", method = RequestMethod.POST) + JsonResponse edit(@RequestBody @Valid CompanyAdminEditRequest request) { + companyAdminService.edit(request); + return JsonResponse.success(); + } + + @ApiOperation(value = "删除") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "IdRequest") + }) + @RequestMapping(value = "/delete", method = RequestMethod.POST) + JsonResponse remove(@RequestBody @Valid IdsRequest request) { + companyAdminService.remove(request); + return JsonResponse.success(); + } + + @ApiOperation(value = "所有") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/find/all", method = RequestMethod.GET) + JsonResponse> all(CompanyAdminPageRequest request) { + List result = companyAdminService.all(request); + return JsonResponse.success(result); + } + +} \ No newline at end of file diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/system/CompanyController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/CompanyController.java new file mode 100644 index 0000000..eb687f7 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/CompanyController.java @@ -0,0 +1,86 @@ +package com.chilunyc.fumao.api.system; + +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.shiro.AuthRoles; +import com.chilunyc.fumao.company.model.Company; +import com.chilunyc.fumao.company.request.company.CompanyEditRequest; +import com.chilunyc.fumao.company.request.company.CompanyPageRequest; +import com.chilunyc.fumao.company.service.CompanyService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +/** + * + */ +@Log4j +@Api(description = "集团") +@RestController +@RequestMapping("/system/company") +@PreAuthorize(AuthRoles.SystemAdminExp) +class CompanyController { + + @Autowired + CompanyService companyService; + + + @ApiOperation(value = "分页") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "PageRequest") + }) + @RequestMapping(value = "/find", method = RequestMethod.POST) + JsonResponse> page(@RequestBody CompanyPageRequest request) { + Page page = companyService.page(request); + return JsonResponse.success(page); + } + + @ApiOperation(value = "详情") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/find/{id}", method = RequestMethod.GET) + JsonResponse info(@PathVariable Long id) { + Company companyResponse = companyService.find(id); + return JsonResponse.success(companyResponse); + } + + + @ApiOperation(value = "新增 | 编辑") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "Company") + }) + @RequestMapping(value = "/edit", method = RequestMethod.POST) + JsonResponse edit(@RequestBody @Valid CompanyEditRequest request) { + Company edit = companyService.edit(request); + return JsonResponse.success(edit); + } + + @ApiOperation(value = "删除") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "IdRequest") + }) + @RequestMapping(value = "/delete", method = RequestMethod.POST) + JsonResponse remove(@RequestBody @Valid IdsRequest request) { + companyService.remove(request); + return JsonResponse.success(); + } + + @ApiOperation(value = "所有") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/find/all", method = RequestMethod.GET) + JsonResponse> all(CompanyPageRequest request) { + List result = companyService.all(request); + return JsonResponse.success(result); + } + +} \ No newline at end of file diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/system/FindPwdController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/FindPwdController.java new file mode 100644 index 0000000..bada19d --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/FindPwdController.java @@ -0,0 +1,54 @@ +package com.chilunyc.fumao.api.system; + +import com.chilunyc.fumao.common.request.ChangePwdRequest; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.sms.model.SmsType; +import com.chilunyc.fumao.common.sms.request.SmsSendRequest; +import com.chilunyc.fumao.common.sms.service.SmsService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.apache.commons.lang3.RandomStringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + +/** + * + */ +@Log4j +@Api(description = "找回密码") +@RestController +@RequestMapping("/system/find/pwd") +class FindPwdController { + + @Autowired + SmsService smsService; + + @ApiOperation(value = "改密码") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "ChangePwdRequest") + }) + @RequestMapping(value = "/", method = RequestMethod.POST) + JsonResponse login(@RequestBody @Valid ChangePwdRequest request) { + return JsonResponse.success(); + } + + @ApiOperation(value = "改密码发短信") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "SmsSendRequest") + }) + @RequestMapping(value = "/send", method = RequestMethod.POST) + JsonResponse login(@RequestBody @Valid SmsSendRequest request) { + request.setContent(RandomStringUtils.randomNumeric(4)); + request.setType(SmsType.CustomerFindPwd); + smsService.send(request); + return JsonResponse.success(); + } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/system/LBSController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/LBSController.java new file mode 100644 index 0000000..f1c36eb --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/LBSController.java @@ -0,0 +1,42 @@ +package com.chilunyc.fumao.api.system; + +import com.chilunyc.fumao.common.lbs.request.LBSPoiRequest; +import com.chilunyc.fumao.common.lbs.service.LBSService; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.shiro.AuthRoles; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + +/** + * + */ +@Log4j +@Api(description = "登录登出") +@RestController +@RequestMapping("/system/lbs") +@PreAuthorize(AuthRoles.SystemAdminExp) +class LBSController { + + @Autowired + LBSService lbsService; + + @ApiOperation(value = "登录") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "LoginRequest") + }) + @RequestMapping(value = "/poi/find", method = RequestMethod.POST) + JsonResponse login(@RequestBody @Valid LBSPoiRequest request) { + return JsonResponse.success(lbsService.findPoi(request)); + } +} \ No newline at end of file diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/system/LoginLogoutController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/LoginLogoutController.java new file mode 100644 index 0000000..d898632 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/LoginLogoutController.java @@ -0,0 +1,52 @@ +package com.chilunyc.fumao.api.system; + +import com.chilunyc.fumao.common.request.LoginRequest; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.util.jwt.JwtUtils; +import com.chilunyc.fumao.system.model.SystemAdmin; +import com.chilunyc.fumao.system.service.SystemAdminService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + +/** + * + */ +@Log4j +@Api(description = "登录登出") +@RestController +@RequestMapping("/system") +class LoginLogoutController { + + @Autowired + SystemAdminService systemAdminService; + + @ApiOperation(value = "登录") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "LoginRequest") + }) + @RequestMapping(value = "/login", method = RequestMethod.POST) + JsonResponse login(@RequestBody @Valid LoginRequest request) { + SystemAdmin systemAdmin = systemAdminService.login(request); + return JsonResponse.success( + JwtUtils.encode(JwtUtils.T.System, systemAdmin) + ); + } + + @ApiOperation(value = "登出") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/logout", method = RequestMethod.GET) + JsonResponse logout() { + return JsonResponse.success(); + } +} \ No newline at end of file diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/system/PlaceAdminController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/PlaceAdminController.java new file mode 100644 index 0000000..516d06d --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/PlaceAdminController.java @@ -0,0 +1,79 @@ +package com.chilunyc.fumao.api.system; + +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.shiro.AuthRoles; +import com.chilunyc.fumao.company.model.PlaceAdmin; +import com.chilunyc.fumao.company.model.enums.PlaceAdminType; +import com.chilunyc.fumao.company.request.placeAdmin.PlaceAdminEditRequest; +import com.chilunyc.fumao.company.request.placeAdmin.PlaceAdminPageRequest; +import com.chilunyc.fumao.company.service.PlaceAdminService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + * + */ +@Log4j +@Api(description = "商场管理员") +@RestController +@RequestMapping("/system/place/admin") +@PreAuthorize(AuthRoles.SystemAdminExp) +class PlaceAdminController { + + @Autowired + PlaceAdminService placeAdminService; + + + @ApiOperation(value = "分页") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "PageRequest") + }) + @RequestMapping(value = "/find", method = RequestMethod.POST) + JsonResponse> page(@RequestBody PlaceAdminPageRequest request) { + Page page = placeAdminService.page(request); + return JsonResponse.success(page); + } + + @ApiOperation(value = "详情") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/find/{id}", method = RequestMethod.GET) + JsonResponse info(@PathVariable Long id) { + PlaceAdmin placeAdminResponse = placeAdminService.find(id); + return JsonResponse.success(placeAdminResponse); + } + + + @ApiOperation(value = "新增 | 编辑") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "PlaceAdmin") + }) + @RequestMapping(value = "/edit", method = RequestMethod.POST) + JsonResponse edit(@RequestBody @Valid PlaceAdminEditRequest request) { + request.setPlaceAdminType(PlaceAdminType.Manager); + placeAdminService.edit(request); + return JsonResponse.success(); + } + + @ApiOperation(value = "删除") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "IdRequest") + }) + @RequestMapping(value = "/delete", method = RequestMethod.POST) + JsonResponse remove(@RequestBody @Valid IdsRequest request) { + placeAdminService.remove(request); + return JsonResponse.success(); + } + + +} \ No newline at end of file diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/system/PlaceController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/PlaceController.java new file mode 100644 index 0000000..48248f5 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/PlaceController.java @@ -0,0 +1,86 @@ +package com.chilunyc.fumao.api.system; + +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.shiro.AuthRoles; +import com.chilunyc.fumao.company.model.Place; +import com.chilunyc.fumao.company.request.place.PlaceEditRequest; +import com.chilunyc.fumao.company.request.place.PlacePageRequest; +import com.chilunyc.fumao.company.service.PlaceService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +/** + * + */ +@Log4j +@Api(description = "商场") +@RestController +@RequestMapping("/system/place") +@PreAuthorize(AuthRoles.SystemAdminExp) +class PlaceController { + + @Autowired + PlaceService placeService; + + + @ApiOperation(value = "分页") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "PageRequest") + }) + @RequestMapping(value = "/find", method = RequestMethod.POST) + JsonResponse> page(@RequestBody PlacePageRequest request) { + Page page = placeService.page(request); + return JsonResponse.success(page); + } + + @ApiOperation(value = "详情") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/find/{id}", method = RequestMethod.GET) + JsonResponse info(@PathVariable Long id) { + Place placeResponse = placeService.find(id); + return JsonResponse.success(placeResponse); + } + + + @ApiOperation(value = "新增 | 编辑") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "Place") + }) + @RequestMapping(value = "/edit", method = RequestMethod.POST) + JsonResponse edit(@RequestBody @Valid PlaceEditRequest request) { + Place edit = placeService.edit(request); + return JsonResponse.success(edit); + } + + @ApiOperation(value = "删除") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "IdRequest") + }) + @RequestMapping(value = "/delete", method = RequestMethod.POST) + JsonResponse remove(@RequestBody @Valid IdsRequest request) { + placeService.remove(request); + return JsonResponse.success(); + } + + @ApiOperation(value = "所有") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/find/all", method = RequestMethod.POST) + JsonResponse> all(@RequestBody PlacePageRequest request) { + List result = placeService.all(request); + return JsonResponse.success(result); + } + +} \ No newline at end of file diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/system/PlaceFloorController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/PlaceFloorController.java new file mode 100644 index 0000000..d65254f --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/PlaceFloorController.java @@ -0,0 +1,78 @@ +package com.chilunyc.fumao.api.system; + +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.shiro.AuthRoles; +import com.chilunyc.fumao.company.model.PlaceFloor; +import com.chilunyc.fumao.company.request.placeFloor.PlaceFloorEditRequest; +import com.chilunyc.fumao.company.request.placeFloor.PlaceFloorPageRequest; +import com.chilunyc.fumao.company.service.PlaceFloorService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +/** + * + */ +@Log4j +@Api(description = "商场楼层") +@RestController +@RequestMapping("/system/place/floor") +@PreAuthorize(AuthRoles.SystemAdminExp) +class PlaceFloorController { + + @Autowired + PlaceFloorService placeFloorService; + + + @ApiOperation(value = "分页") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "PageRequest") + }) + @RequestMapping(value = "/find/all", method = RequestMethod.POST) + JsonResponse> all(@RequestBody PlaceFloorPageRequest request) { + List page = placeFloorService.all(request); + return JsonResponse.success(page); + } + + @ApiOperation(value = "详情") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/find/{id}", method = RequestMethod.GET) + JsonResponse info(@PathVariable Long id) { + PlaceFloor placeFloorResponse = placeFloorService.find(id); + return JsonResponse.success(placeFloorResponse); + } + + + @ApiOperation(value = "新增 | 编辑") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "PlaceFloor") + }) + @RequestMapping(value = "/edit", method = RequestMethod.POST) + JsonResponse edit(@RequestBody @Valid PlaceFloorEditRequest request) { + placeFloorService.edit(request); + return JsonResponse.success(); + } + + @ApiOperation(value = "删除") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "IdRequest") + }) + @RequestMapping(value = "/delete", method = RequestMethod.POST) + JsonResponse remove(@RequestBody @Valid IdsRequest request) { + placeFloorService.remove(request); + return JsonResponse.success(); + } + + +} \ No newline at end of file diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/system/ShopApplyController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/ShopApplyController.java new file mode 100644 index 0000000..2d5de8f --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/ShopApplyController.java @@ -0,0 +1,65 @@ +package com.chilunyc.fumao.api.system; + +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.shiro.AuthRoles; +import com.chilunyc.fumao.company.model.ShopApply; +import com.chilunyc.fumao.company.request.shopApply.ShopApplyEditRequest; +import com.chilunyc.fumao.company.request.shopApply.ShopApplyPageRequest; +import com.chilunyc.fumao.company.service.ShopApplyService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + * + */ +@Log4j +@Api(description = "商铺申请") +@RestController +@RequestMapping("/system/shop/apply") +@PreAuthorize(AuthRoles.SystemAdminExp) +class ShopApplyController { + + @Autowired + ShopApplyService shopApplyService; + + @ApiOperation(value = "分页") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "PageRequest") + }) + @RequestMapping(value = "/find", method = RequestMethod.POST) + JsonResponse> page(@RequestBody ShopApplyPageRequest request) { + Page page = shopApplyService.page(request); + return JsonResponse.success(page); + } + + @ApiOperation(value = "详情") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/find/{id}", method = RequestMethod.GET) + JsonResponse info(@PathVariable Long id) { + ShopApply shopApplyResponse = shopApplyService.find(id); + return JsonResponse.success(shopApplyResponse); + } + + + @ApiOperation(value = "删除") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "IdRequest") + }) + @RequestMapping(value = "/delete", method = RequestMethod.POST) + JsonResponse remove(@RequestBody @Valid IdsRequest request) { + shopApplyService.remove(request); + return JsonResponse.success(); + } + +} \ No newline at end of file diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/api/system/SystemAdminController.java b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/SystemAdminController.java new file mode 100644 index 0000000..6cc3804 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/api/system/SystemAdminController.java @@ -0,0 +1,77 @@ +package com.chilunyc.fumao.api.system; + +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.shiro.AuthRoles; +import com.chilunyc.fumao.system.model.SystemAdmin; +import com.chilunyc.fumao.system.request.systemAdmin.SystemAdminEditRequest; +import com.chilunyc.fumao.system.request.systemAdmin.SystemAdminPageRequest; +import com.chilunyc.fumao.system.service.SystemAdminService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + * + */ +@Log4j +@Api(description = "系统管理员") +@RestController +@RequestMapping("/system/admin") +@PreAuthorize(AuthRoles.SystemAdminExp) +class SystemAdminController { + + @Autowired + SystemAdminService systemAdminService; + + + @ApiOperation(value = "分页") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "PageRequest") + }) + @RequestMapping(value = "/find", method = RequestMethod.POST) + JsonResponse> page(@RequestBody SystemAdminPageRequest request) { + Page page = systemAdminService.page(request); + return JsonResponse.success(page); + } + + @ApiOperation(value = "详情") + @ApiImplicitParams({ + }) + @RequestMapping(value = "/find/{id}", method = RequestMethod.GET) + JsonResponse info(@PathVariable Long id) { + SystemAdmin systemAdminResponse = systemAdminService.find(id); + return JsonResponse.success(systemAdminResponse); + } + + + @ApiOperation(value = "新增 | 编辑") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "SystemAdmin") + }) + @RequestMapping(value = "/edit", method = RequestMethod.POST) + JsonResponse edit(@RequestBody @Valid SystemAdminEditRequest request) { + systemAdminService.edit(request); + return JsonResponse.success(); + } + + @ApiOperation(value = "删除") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "IdRequest") + }) + @RequestMapping(value = "/delete", method = RequestMethod.POST) + JsonResponse remove(@RequestBody @Valid IdsRequest request) { + systemAdminService.remove(request); + return JsonResponse.success(); + } + + +} \ No newline at end of file diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/config/bean/MultiBeanNameGenerator.java b/fumao-app/src/main/java/com/chilunyc/fumao/config/bean/MultiBeanNameGenerator.java new file mode 100644 index 0000000..29a1729 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/config/bean/MultiBeanNameGenerator.java @@ -0,0 +1,21 @@ +package com.chilunyc.fumao.config.bean; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.annotation.AnnotationBeanNameGenerator; + +/** + * + */ +public class MultiBeanNameGenerator extends AnnotationBeanNameGenerator { + + @Override + public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) { + String beanClassName = beanDefinition.getBeanClassName(); + if (StringUtils.startsWith(beanClassName, "com.chilunyc") && StringUtils.endsWith(beanClassName, "Controller")) { + return beanClassName; + } + return super.generateBeanName(beanDefinition, beanDefinitionRegistry); + } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/config/captcha/CaptchaConfig.java b/fumao-app/src/main/java/com/chilunyc/fumao/config/captcha/CaptchaConfig.java new file mode 100644 index 0000000..10276b6 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/config/captcha/CaptchaConfig.java @@ -0,0 +1,32 @@ +package com.chilunyc.fumao.config.captcha; + +import com.google.code.kaptcha.impl.DefaultKaptcha; +import com.google.code.kaptcha.util.Config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Properties; + +/** + * + */ +@Configuration +public class CaptchaConfig { + + @Bean + public DefaultKaptcha captchaProducer() { + DefaultKaptcha captchaProducer = new DefaultKaptcha(); + Properties properties = new Properties(); + properties.setProperty("kaptcha.border", "yes"); + properties.setProperty("kaptcha.border.color", "105,179,90"); + properties.setProperty("kaptcha.textproducer.font.color", "blue"); + properties.setProperty("kaptcha.image.width", "150"); + properties.setProperty("kaptcha.image.height", "60"); + properties.setProperty("kaptcha.textproducer.font.size", "45"); + properties.setProperty("kaptcha.session.key", "code"); + properties.setProperty("kaptcha.textproducer.char.length", "4"); + Config config = new Config(properties); + captchaProducer.setConfig(config); + return captchaProducer; + } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/config/swagger/SwaggerConfig.java b/fumao-app/src/main/java/com/chilunyc/fumao/config/swagger/SwaggerConfig.java new file mode 100644 index 0000000..bc4386c --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/config/swagger/SwaggerConfig.java @@ -0,0 +1,76 @@ +package com.chilunyc.fumao.config.swagger; + +import com.chilunyc.fumao.common.response.JsonResponse; +import com.fasterxml.classmate.TypeResolver; +import com.google.common.base.Predicate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.ResponseEntity; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.schema.AlternateTypeRules; +import springfox.documentation.schema.WildcardType; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +/** + * + */ +@Configuration +@ConditionalOnProperty(value = "app.test", havingValue = "true") +@EnableSwagger2 +public class SwaggerConfig { + + @Autowired + private TypeResolver typeResolver; + + @Bean + Docket all() { + return build("所有", "/", "所有接口"); + } + + /** + * @param group + * @param path + * @param title + * @return + */ + Docket build(String group, String path, String title) { + return new Docket(DocumentationType.SWAGGER_2) + .select() + .paths(includePath(path)) + .build() + .groupName(group) + .ignoredParameterTypes( + ) + .apiInfo( + new ApiInfoBuilder() + .title(title) + .version("1.0") + .build()) + .genericModelSubstitutes(ResponseEntity.class) + .alternateTypeRules( + AlternateTypeRules.newRule( + typeResolver.resolve(ResponseEntity.class, typeResolver.resolve(JsonResponse.class, WildcardType.class)), + typeResolver.resolve(WildcardType.class) + ) + ) + .useDefaultResponseMessages(false) + ; + } + + /** + * @param path + * @return + */ + Predicate includePath(final String path) { + return new Predicate() { + @Override + public boolean apply(String input) { + return input.startsWith(path); + } + }; + } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/config/web/JsonConfig.java b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/JsonConfig.java new file mode 100644 index 0000000..19add0e --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/JsonConfig.java @@ -0,0 +1,21 @@ +package com.chilunyc.fumao.config.web; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import org.springframework.boot.jackson.JsonComponent; + +import java.io.IOException; + +/** + * + */ +@JsonComponent +public class JsonConfig extends JsonDeserializer { + + @Override + public String deserialize(JsonParser parser, DeserializationContext context) throws IOException { + return parser.hasToken(JsonToken.VALUE_STRING) ? parser.getText().trim() : null; + } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/config/web/WebConfig.java b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/WebConfig.java new file mode 100644 index 0000000..d2173a2 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/WebConfig.java @@ -0,0 +1,78 @@ +package com.chilunyc.fumao.config.web; + +import com.chilunyc.fumao.common.config.ApplicationProperty; +import com.chilunyc.fumao.config.web.arguments.DateArgumentResolver; +import com.chilunyc.fumao.config.web.arguments.LoginUserArgumentResolver; +import com.chilunyc.fumao.config.web.interceptor.AuthInterceptor; +import com.chilunyc.fumao.config.web.interceptor.CorsInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +import java.util.List; + +/** + * + */ +@Configuration +public class WebConfig extends WebMvcConfigurerAdapter { + + @Autowired + private AuthInterceptor authInterceptor; + + @Autowired + private CorsInterceptor corsInterceptor; + + @Autowired + private LoginUserArgumentResolver jwtValueArgumentResolver; + + @Autowired + private ApplicationProperty applicationConfig; + + /** + * 跨域访问 + * + * @param registry + */ + @Override + public void addCorsMappings(CorsRegistry registry) { + registry + .addMapping("/**/*") + .allowedOrigins("*") + .allowedMethods("*") + .allowedHeaders("*") + .allowCredentials(true) + ; + } + + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(corsInterceptor); +// registry.addInterceptor(authInterceptor).excludePathPatterns( +// "/**/login", +// "/**/login/**", +// "/**/logout", +// "/upload", +// "/**/register/**", +// "/**/find/pwd/", +// "/**/find/pwd/**", +// "/swagger/**", +// "/swagger-resources/**", +// "/webjars/**", +// "/captcha", +// "/wx/**", +// "/error" +// ); + } + + @Override + public void addArgumentResolvers(List argumentResolvers) { + argumentResolvers.add(jwtValueArgumentResolver); + argumentResolvers.add(new DateArgumentResolver()); + } + +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/config/web/WebSecurityConfig.java b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/WebSecurityConfig.java new file mode 100644 index 0000000..068cc33 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/WebSecurityConfig.java @@ -0,0 +1,58 @@ +package com.chilunyc.fumao.config.web; + +import com.chilunyc.fumao.config.web.security.SecurityFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +/** + * Created by Tkk on 2018/7/23. + */ +@Configuration +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + + @Autowired + SecurityFilter securityFilter; + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + // 开启跨域 + .cors() + + // 取消session + .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER) + + // 关闭csrf + .and().csrf().disable() + + + .authorizeRequests() + + // 放行登录 + .antMatchers( + "/login", + "/login/**", + "/**/login", + "/**/login/**") + .permitAll() + + // 放行通用 + .antMatchers( + "/common/**") + .permitAll() + + // 其他全部校验 + .anyRequest() + .authenticated() + + // 增加过滤器, 过滤权限 + .and() + .addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class); + + } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/config/web/arguments/DateArgumentResolver.java b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/arguments/DateArgumentResolver.java new file mode 100644 index 0000000..330cdb7 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/arguments/DateArgumentResolver.java @@ -0,0 +1,38 @@ +package com.chilunyc.fumao.config.web.arguments; + +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.time.DateUtils; +import org.springframework.core.MethodParameter; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +import java.util.Date; + +/** + * + */ +public class DateArgumentResolver implements HandlerMethodArgumentResolver { + + @Override + public boolean supportsParameter(MethodParameter methodParameter) { + return ClassUtils.isAssignable(methodParameter.getParameterType(), Date.class); + } + + @Override + public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception { + String parameterName = methodParameter.getParameterName(); + String value = nativeWebRequest.getParameter(parameterName); + if (StringUtils.isBlank(value) || StringUtils.equalsIgnoreCase("undefined", value)) { + return null; + } else if (value.length() <= 10) { + return DateUtils.parseDate(value, "yyyy-MM-dd"); + } else if (value.length() > 16) { + return DateUtils.parseDate(value, "yyyy-MM-dd HH:mm:ss"); + } else { + return null; + } + } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/config/web/arguments/LoginUserArgumentResolver.java b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/arguments/LoginUserArgumentResolver.java new file mode 100644 index 0000000..2a867b1 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/arguments/LoginUserArgumentResolver.java @@ -0,0 +1,34 @@ +package com.chilunyc.fumao.config.web.arguments; + +import com.chilunyc.fumao.common.context.RequestHolder; +import com.chilunyc.fumao.common.exception.SystemException; +import com.chilunyc.fumao.common.context.LoginUser; +import io.jsonwebtoken.Claims; +import org.apache.commons.lang3.ClassUtils; +import org.springframework.core.MethodParameter; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +/** + * + */ +@Component +public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver { + + @Override + public boolean supportsParameter(MethodParameter methodParameter) { + return ClassUtils.isAssignable(methodParameter.getParameterType(), LoginUser.class); + } + + @Override + public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception { + LoginUser o = (LoginUser) methodParameter.getParameterType().newInstance(); + Claims jwtValue = RequestHolder.get().getJwtValue(); + o.fromJwt(jwtValue); + return o; + } + +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/config/web/interceptor/AuthInterceptor.java b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/interceptor/AuthInterceptor.java new file mode 100644 index 0000000..9e72ad9 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/interceptor/AuthInterceptor.java @@ -0,0 +1,36 @@ +package com.chilunyc.fumao.config.web.interceptor; + +import com.chilunyc.fumao.common.config.ApplicationProperty; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * + */ +@Component +public class AuthInterceptor extends HandlerInterceptorAdapter { + + @Autowired + private ApplicationProperty applicationProperty; + + + /** + * 做权限过滤 + * + * @param servletRequest + * @param response + * @param handler + * @return + * @throws Exception + */ + @Override + public boolean preHandle(HttpServletRequest servletRequest, HttpServletResponse response, Object handler) throws Exception { + return true; + + } + +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/config/web/interceptor/CorsInterceptor.java b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/interceptor/CorsInterceptor.java new file mode 100644 index 0000000..8952e8b --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/interceptor/CorsInterceptor.java @@ -0,0 +1,54 @@ +package com.chilunyc.fumao.config.web.interceptor; + +import com.chilunyc.fumao.common.context.RequestHolder; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.servlet.handler.AbstractHandlerMapping; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.Map; + +/** + * + */ +@Component +public class CorsInterceptor extends HandlerInterceptorAdapter implements ApplicationContextAware { + + private AbstractHandlerMapping handlerMapping; + private CorsConfiguration cors; + private ApplicationContext applicationContext; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + if (handlerMapping == null) { + synchronized (applicationContext) { + if (handlerMapping == null) { + handlerMapping = applicationContext.getBean(AbstractHandlerMapping.class); + Map corsConfigurations = handlerMapping.getCorsConfigurations(); + this.cors = new ArrayList<>(corsConfigurations.values()).get(0); + } + } + } + + // + handlerMapping.getCorsProcessor().processRequest(cors, request, response); + return super.preHandle(request, response, handler); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + super.afterCompletion(request, response, handler, ex); + RequestHolder.clean(); + } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/config/web/security/SecurityEntryPoint.java b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/security/SecurityEntryPoint.java new file mode 100644 index 0000000..b25fe4a --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/security/SecurityEntryPoint.java @@ -0,0 +1,26 @@ +package com.chilunyc.fumao.config.web.security; + +import com.chilunyc.fumao.common.response.JsonResponse; +import lombok.extern.log4j.Log4j; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Created by Tkk on 2018/7/23. + */ +@Log4j +@Component +public class SecurityEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { + httpServletResponse.setContentType("application/json"); + httpServletResponse.getWriter().write(JsonResponse.fail("000002", "尚未登录").toString()); + } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/config/web/security/SecurityFilter.java b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/security/SecurityFilter.java new file mode 100644 index 0000000..83856c3 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/config/web/security/SecurityFilter.java @@ -0,0 +1,141 @@ +package com.chilunyc.fumao.config.web.security; + +import com.chilunyc.fumao.common.context.Request; +import com.chilunyc.fumao.common.context.RequestHolder; +import com.chilunyc.fumao.common.exception.SystemException; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.shiro.AuthUser; +import com.chilunyc.fumao.common.util.jwt.JwtUtils; +import com.chilunyc.fumao.config.web.arguments.LoginUserArgumentResolver; +import io.jsonwebtoken.Claims; +import lombok.extern.log4j.Log4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.springframework.context.NoSuchMessageException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; +import org.springframework.web.util.ContentCachingRequestWrapper; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; + +/** + * 把JWT转换为security的对象 + * Created by Tkk on 2018/7/23. + */ +@Component +@Log4j +public class SecurityFilter extends OncePerRequestFilter { + + @Autowired + MessageSource messageSource; + + @Override + protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { + // 区分什么请求 + Request build = Request + .builder() + .request(httpServletRequest) + .build(); + String servletPath = httpServletRequest.getServletPath(); + String prefix = org.apache.commons.lang3.StringUtils.substringBetween(servletPath, "/", "/"); + switch (prefix) { + case "system": + build.setJwtType(JwtUtils.T.System); + break; + case "company": + build.setJwtType(JwtUtils.T.Company); + break; + case "place": + build.setJwtType(JwtUtils.T.Market); + break; + case "customer": + build.setJwtType(JwtUtils.T.APP_C); + break; + case "merchant": + build.setJwtType(JwtUtils.T.APP_B); + break; + } + + try { + RequestHolder.set(build); + String token = httpServletRequest.getHeader("token"); + if (StringUtils.isNotBlank(token)) { + // + Claims claims = JwtUtils.decode(build.getJwtType(), httpServletRequest.getHeader("token")); + AuthUser authUser = toAuthUser(claims); + + // 放入jwt数值, 用于后面转换方法对面 + build.setJwtValue(claims); + + // 如果能转换成功, 说明登录没问题, 那么转换为security对象, 做权限处理 + UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = toAuthToken(authUser); + SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); + } + + // 包装request对象, 可以之后做日志处理, 可以反复读取请求体 + ContentCachingRequestWrapper r = new ContentCachingRequestWrapper(httpServletRequest); + filterChain.doFilter(r, httpServletResponse); + } + // 业务一次 + catch (SystemException e) { + log.error(e.getMessage(), e); + httpServletResponse.setCharacterEncoding("UTF-8"); + httpServletResponse.getWriter().write( + JsonResponse.fail(e.getErrorCode(), getMessage(e.getErrorCode(), e.getParams())).toString() + ); + } + // 所有异常 + catch (Exception e) { + log.error(e.getMessage(), e); + httpServletResponse.setCharacterEncoding("UTF-8"); + httpServletResponse.getWriter().write( + JsonResponse.fail().toString() + ); + } finally { + RequestHolder.clean(); + } + } + + /** + * @param claims + * @return + */ + private AuthUser toAuthUser(Claims claims) { + List roles = (List) claims.get("role"); + if (roles == null) { + roles = Collections.emptyList(); + } + return AuthUser + .builder() + .id(Long.parseLong(claims.getSubject())) + .authorities( + roles.stream() + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList())) + .build(); + } + + private UsernamePasswordAuthenticationToken toAuthToken(AuthUser authUser) { + return new UsernamePasswordAuthenticationToken(authUser, null, authUser.getAuthorities()); + } + + protected String getMessage(String code, Object[] params) { + try { + return messageSource.getMessage(code, params, Locale.CHINA); + } catch (NoSuchMessageException e) { + return code; + } + } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/controller/FindPwdController.java b/fumao-app/src/main/java/com/chilunyc/fumao/controller/FindPwdController.java new file mode 100644 index 0000000..cd62499 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/controller/FindPwdController.java @@ -0,0 +1,62 @@ +package com.chilunyc.fumao.controller; + +import com.chilunyc.fumao.common.request.ChangePwdRequest; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.sms.model.SmsType; +import com.chilunyc.fumao.common.sms.request.SmsSendRequest; +import com.chilunyc.fumao.common.sms.service.SmsService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j; +import org.apache.commons.lang3.RandomStringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + +/** + * + */ +@Log4j +@Api(description = "找回密码") +@RestController +@RequestMapping("/find/pwd") +class FindPwdController { + + @Autowired + SmsService smsService; + + + @ApiOperation(value = "改密码") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "UserChangePwdRequest") + }) + @RequestMapping(value = "/", method = RequestMethod.POST) + JsonResponse login(@RequestBody @Valid ChangePwdRequest request) { +// + return JsonResponse.success(); + } + + @ApiOperation(value = "改密码发短信") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "SmsSendRequest") + }) + @RequestMapping(value = "/send", method = RequestMethod.POST) + JsonResponse login(@RequestBody @Valid SmsSendRequest request) { + //1. 校验是否存在 +// if (!userService.isExist(request.getMobile())) { +// throw new SystemException("000010"); +// } + + //2. 发送 + request.setContent(RandomStringUtils.randomNumeric(4)); + request.setType(SmsType.CustomerFindPwd); + smsService.send(request); + return JsonResponse.success(); + } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/controller/common/CaptchaController.java b/fumao-app/src/main/java/com/chilunyc/fumao/controller/common/CaptchaController.java new file mode 100644 index 0000000..33cef47 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/controller/common/CaptchaController.java @@ -0,0 +1,58 @@ +package com.chilunyc.fumao.controller.common; + +import com.google.code.kaptcha.Constants; +import com.google.code.kaptcha.Producer; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.servlet.ModelAndView; + +import javax.imageio.ImageIO; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.awt.image.BufferedImage; + +/** + * + */ +@Api(description = "验证码") +@Controller +@RequestMapping("/common/captcha") +class CaptchaController { + + @Autowired + Producer captchaProducer; + + /** + * 验证码 + * + * @param response + * @param session + * @return + * @throws Exception + */ + @ApiOperation(value = "生成验证码图片") + @RequestMapping(value = "", method = RequestMethod.GET) + ModelAndView index(HttpServletResponse response, HttpSession session) throws Exception { + response.setDateHeader("Expires", 0); + response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate"); + response.addHeader("Cache-Control", "post-checkExist=0, pre-checkExist=0"); + response.setHeader("Pragma", "no-cache"); + response.setContentType("image/jpeg"); + String capText = captchaProducer.createText(); + session.setAttribute(Constants.KAPTCHA_SESSION_KEY, capText); + BufferedImage bi = captchaProducer.createImage(capText); + ServletOutputStream out = response.getOutputStream(); + ImageIO.write(bi, "jpg", out); + try { + out.flush(); + } finally { + out.close(); + } + return null; + } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/controller/common/LogController.java b/fumao-app/src/main/java/com/chilunyc/fumao/controller/common/LogController.java new file mode 100644 index 0000000..d8b40e9 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/controller/common/LogController.java @@ -0,0 +1,43 @@ +package com.chilunyc.fumao.controller.common; + +import com.chilunyc.fumao.common.log.repository.EventMapper; +import com.chilunyc.fumao.common.log.request.LogPageRequest; +import com.chilunyc.fumao.common.log.response.LogResponse; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.github.pagehelper.Page; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import org.apache.ibatis.session.RowBounds; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageImpl; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** + * + */ +@Api("日志") +@RestController +@RequestMapping("/log") +class LogController { + + @Autowired + EventMapper eventMapper; + + @ApiOperation(value = "分页") + @ApiImplicitParams({ + @ApiImplicitParam(name = "request", required = true, paramType = "body", dataType = "LogPageRequest") + }) + @RequestMapping(value = "", method = RequestMethod.POST) + JsonResponse page(@RequestBody LogPageRequest request) { + RowBounds rowBounds = new RowBounds(request.getStart(), request.getSize()); + Page page = eventMapper.page(request, rowBounds); + return JsonResponse.success( + new PageImpl<>(page, request.getPage(), page.getTotal()) + ); + } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/controller/common/UploadController.java b/fumao-app/src/main/java/com/chilunyc/fumao/controller/common/UploadController.java new file mode 100644 index 0000000..1213bc5 --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/controller/common/UploadController.java @@ -0,0 +1,34 @@ +package com.chilunyc.fumao.controller.common; + +import com.chilunyc.fumao.common.context.LoginUser; +import com.chilunyc.fumao.common.response.JsonResponse; +import com.chilunyc.fumao.common.upload.response.UploadResponse; +import com.chilunyc.fumao.common.upload.service.UploadService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** + * + */ +@Api(description = "上传服务") +@RestController +@RequestMapping("/upload") +class UploadController { + + @Autowired + UploadService uploadService; + + /** + * @return + */ + @ApiOperation(value = "获取上传凭证") + @RequestMapping(value = "", method = RequestMethod.GET) + ResponseEntity> index(LoginUser loginUser) { + return ResponseEntity.ok(JsonResponse.success(uploadService.getAuth())); + } +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/controller/error/ExceptionController.java b/fumao-app/src/main/java/com/chilunyc/fumao/controller/error/ExceptionController.java new file mode 100644 index 0000000..63d55be --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/controller/error/ExceptionController.java @@ -0,0 +1,177 @@ +package com.chilunyc.fumao.controller.error; + +import com.chilunyc.fumao.common.config.ApplicationProperty; +import com.chilunyc.fumao.common.exception.SystemException; +import com.chilunyc.fumao.common.log.model.EventTarget; +import com.chilunyc.fumao.common.log.model.EventType; +import com.chilunyc.fumao.common.log.service.EventService; +import com.chilunyc.fumao.common.context.RequestHolder; +import com.chilunyc.fumao.common.response.JsonResponse; +import lombok.extern.log4j.Log4j; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.springframework.context.NoSuchMessageException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.http.HttpStatus; +import org.springframework.validation.BindException; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.util.ContentCachingRequestWrapper; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +/** + * + */ +@Log4j +@ControllerAdvice +class ExceptionController { + + @Autowired + MessageSource messageSource; + + @Autowired + EventService eventService; + + @Autowired + ApplicationProperty applicationProperty; + + /** + * 业务异常 + * + * @param request + * @param ex + * @return + */ + @ExceptionHandler(SystemException.class) + @ResponseStatus(HttpStatus.OK) + @ResponseBody + JsonResponse systemExceptionHandler(ContentCachingRequestWrapper request, SystemException ex) { + String errorCode = ex.getErrorCode(); + if (StringUtils.isEmpty(errorCode)) { + errorCode = "000001"; + } + String msg = this.getMessage(errorCode, ex.getParams()); + String requestContent = ""; + try { + requestContent = IOUtils.toString(request.getContentAsByteArray(), "UTF-8"); + } catch (Exception e) { + } + if (applicationProperty.isTest()) { + log.error(request.getServletPath() + " => " + errorCode + " => " + requestContent + " ==> " + msg, ex); + } else { + String errorMsg = request.getServletPath() + " => " + errorCode + " => " + requestContent + " ==> " + msg + " || " + this.getStackJson(ex); + eventService.add(RequestHolder.get(), EventTarget.None, EventType.Error, null, errorMsg); + } + return JsonResponse.fail(errorCode, msg); + } + + /** + * 参数验证 + * + * @param ex + * @return + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseStatus(HttpStatus.OK) + @ResponseBody + JsonResponse validationHandler(MethodArgumentNotValidException ex) { + List fieldErrors = ex.getBindingResult().getFieldErrors(); + FieldError fr = fieldErrors.get(fieldErrors.size() - 1); + return JsonResponse.fail("000003", fr.getDefaultMessage()); + } + + /** + * 参数验证 + * + * @param ex + * @return + */ + @ExceptionHandler(BindException.class) + @ResponseStatus(HttpStatus.OK) + @ResponseBody + JsonResponse validationHandler(BindException ex) { + List fieldErrors = ex.getBindingResult().getFieldErrors(); + FieldError fr = fieldErrors.get(fieldErrors.size() - 1); + return JsonResponse.fail("000003", fr.getDefaultMessage()); + } + + /** + * 数据不存在 + * + * @param ex + * @return + */ + @ExceptionHandler(EmptyResultDataAccessException.class) + @ResponseStatus(HttpStatus.OK) + @ResponseBody + JsonResponse noDataHandler(EmptyResultDataAccessException ex) { + log.error(ex.getMessage(), ex); + return JsonResponse.fail("000004", this.getMessage("000004", null)); + } + + /** + * 错误统一处理 + * + * @param request + * @param ex + * @return + * @throws Exception + */ + @ExceptionHandler + @ResponseBody + JsonResponse defaultExceptionHandler(ContentCachingRequestWrapper request, Exception ex) throws Exception { + String requestContent = ""; + try { + requestContent = IOUtils.toString(request.getContentAsByteArray(), "UTF-8"); + } catch (Exception e) { + } + if (applicationProperty.isTest()) { + log.error(request.getServletPath() + " => " + requestContent + " ==> " + ex.getMessage(), ex); + return JsonResponse.fail(ex.getMessage()); + } else { + String errorMsg = request.getServletPath() + " => " + requestContent + " ==> " + ex.getMessage() + " || " + this.getStackJson(ex); + eventService.add(RequestHolder.get(), EventTarget.None, EventType.Error, null, errorMsg); + return JsonResponse.fail(); + } + } + + protected String getMessage(String code, Object[] params) { + try { + return messageSource.getMessage(code, params, Locale.CHINA); + } catch (NoSuchMessageException e) { + return code; + } + } + + private String getStackJson(Throwable e) { + String result = ""; + if (null != e) { + StackTraceElement[] s = e.getStackTrace(); + if (null != s) { + if (s.length > 10) { + s = Arrays.copyOfRange(s, 0, 9); + } + result = "\n"; + for (StackTraceElement ste : s) { + result += ("\tat " + ste + "\n"); + } + if (null != e.getCause()) { + result += "Cause By:" + StringUtils.trimToEmpty(e.getCause().getMessage()); + result += getStackJson(e.getCause()); + } + } + } + return result; + } + + +} diff --git a/fumao-app/src/main/java/com/chilunyc/fumao/controller/error/PanicController.java b/fumao-app/src/main/java/com/chilunyc/fumao/controller/error/PanicController.java new file mode 100644 index 0000000..0ed66db --- /dev/null +++ b/fumao-app/src/main/java/com/chilunyc/fumao/controller/error/PanicController.java @@ -0,0 +1,44 @@ +package com.chilunyc.fumao.controller.error; + +import com.chilunyc.fumao.common.response.JsonResponse; +import com.alibaba.fastjson.JSON; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.web.ErrorAttributes; +import org.springframework.boot.autoconfigure.web.ErrorController; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * + */ +@Log4j +@RestController +@RequestMapping("/error") +public class PanicController implements ErrorController { + + @Autowired + ErrorAttributes errorAttributes; + + @Autowired + ExceptionController exceptionController; + + @Override + public String getErrorPath() { + return "/error"; + } + + @RequestMapping + public JsonResponse error(HttpServletRequest aRequest) throws Exception { + RequestAttributes requestAttributes = new ServletRequestAttributes(aRequest); + Map errorAttributes = this.errorAttributes.getErrorAttributes(requestAttributes, false); + log.error(String.format("[%s] => [%s]", errorAttributes.get("path"), JSON.toJSONString(errorAttributes))); + return errorAttributes.get("error") != null ? JsonResponse.fail(errorAttributes.get("error").toString()) : JsonResponse.fail(); + } + +} diff --git a/fumao-app/src/main/resources/application.prod.properties b/fumao-app/src/main/resources/application.prod.properties new file mode 100644 index 0000000..eab43b2 --- /dev/null +++ b/fumao-app/src/main/resources/application.prod.properties @@ -0,0 +1,111 @@ +###### +## +###### +logging.level.root=INFO +logging.level.com.aki=INFO +logging.level.org.springframework=INFO +logging.config=/opt/projects/config/logback.xml + +###### +## +###### +server.address=127.0.0.1 +server.port=8088 +spring.data.redis.repositories.enabled=false +server.undertow.io-threads=100 + +###### +## spring boot admin +###### +#spring.boot.admin.url=http://localhost:18081 +endpoints.enabled=false +#endpoints.metrics.endabled=true +#endpoints.health.endabled=true +#endpoints.dump.endabled=true +#management.context-path=/monitor +#management.security.enabled=false + +###### +## +###### +app.test=false +app.role=true +app.save-error=true +app.config-path=classpath:/config.json + + +###### +## \u90AE\u4EF6\u53D1\u9001 +###### +#spring.mail.host= +#spring.mail.username= +#spring.mail.password= +#spring.mail.properties.mail.smtp.auth=true +#spring.mail.properties.mail.smtp.starttls.enable=true +#spring.mail.properties.mail.smtp.starttls.required=true + +###### +## redis +###### +spring.redis.host=127.0.0.1 +spring.redis.port=6379 +spring.redis.pool.max-idle=50 +spring.redis.pool.min-idle=50 +spring.redis.pool.max-active=50 +spring.redis.pool.max-wait=-1 + +###### +## \u6570\u636E\u6E90 +###### +mybatis.mapper-locations=classpath*:com/aki/**/*Mapper.xml +mybatis.configuration.default-fetch-size=100 +mybatis.configuration.default-statement-timeout=30 +mybatis.configuration.map-underscore-to-camel-case=true +pagehelper.helperDialect=mysql +pagehelper.reasonable=true +pagehelper.row-bounds-with-count=true +pagehelper.supportMethodsArguments=tru +spring.jpa.open-in-view=false +spring.datasource.url= +spring.datasource.username= +spring.datasource.password= +spring.datasource.initial-size=20 +spring.datasource.min-idle=20 +spring.datasource.max-idle=100 +spring.datasource.max-wait=10000 +spring.datasource.testOnBorrow=true +spring.datasource.validation-query=SELECT 1 + +##### +## \u963F\u91CC\u4E91 - OSS +###### +aliyun.oss.access-id= +aliyun.oss.access-key= +aliyun.oss.end-point= +aliyun.oss.bucket= + +###### +## \u963F\u91CC\u4E91 - \u77ED\u4FE1 +###### +aliyun.sms.type=sms +aliyun.sms.access-id= +aliyun.sms.access-key= +aliyun.sms.end-point= +aliyun.sms.sign-name= +aliyun.sms.param-name=content +aliyun.sms.topic= +aliyun.sms.expired-duration=2 + +###### +## \u5FAE\u4FE1 +###### +wechat.mp.app-id= +wechat.mp.secret= +wechat.mp.token= +wechat.mp.aesKey= +wechat.mp.mch-id= +wechat.mp.mch-key= +wechat.mp.key-path= + +wechat.ma.app-id= +wechat.ma.secret= \ No newline at end of file diff --git a/fumao-app/src/main/resources/application.properties b/fumao-app/src/main/resources/application.properties new file mode 100644 index 0000000..7c37b51 --- /dev/null +++ b/fumao-app/src/main/resources/application.properties @@ -0,0 +1,99 @@ +###### +## +###### +logging.level.root=INFO +logging.level.com.aki=TRACE +logging.level.org.springframework=INFO +logging.level.org.hibernate=INFO + +###### +## +###### +server.address=0.0.0.0 +server.port=8088 +server.session.timeout=36000000 +spring.data.redis.repositories.enabled=false +spring.output.ansi.enabled=ALWAYS + +###### +## spring boot admin +###### +#spring.boot.admin.url=http://localhost:18081 +#endpoints.enabled=false +#endpoints.metrics.endabled=true +#endpoints.health.endabled=true +#endpoints.dump.endabled=true +management.context-path=/monitor +management.security.enabled=false + +###### +## \u7CFB\u7EDF\u914D\u7F6E +###### +app.test=true +app.role=true +app.cache-time=3600 +app.save-error=false +app.config-path=classpath:config.json + +###### +## \u6570\u636E\u6E90 +###### +mybatis.mapper-locations=classpath*:com/chilunyc/**/*Mapper.xml +mybatis.configuration.default-fetch-size=100 +mybatis.configuration.default-statement-timeout=30 +mybatis.configuration.map-underscore-to-camel-case=true +pagehelper.helperDialect=mysql +pagehelper.reasonable=true +pagehelper.row-bounds-with-count=true +pagehelper.supportMethodsArguments=true +spring.jpa.hibernate.ddl-auto=update +spring.jpa.show-sql=true +spring.jpa.open-in-view=false +spring.datasource.testOnBorrow=true +spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo?characterEncoding=UTF-8&&zeroDateTimeBehavior=convertToNull&autoReconnect=true&failOverReadOnly=false&connectTimeout=0 +#spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo?characterEncoding=UTF-8&&zeroDateTimeBehavior=convertToNull&autoReconnect=true&failOverReadOnly=false&connectTimeout=0&useSSL=true +spring.datasource.username=root +spring.datasource.password= + +###### +## redis +###### +spring.redis.host=127.0.0.1 +#spring.redis.password= +spring.redis.port=6379 +spring.redis.pool.max-idle=10 +spring.redis.pool.min-idle=10 +spring.redis.pool.max-active=10 +spring.redis.pool.max-wait=-1 + +###### +## \u963F\u91CC\u4E91 - OSS +###### +aliyun.oss.access-id= +aliyun.oss.access-key= +aliyun.oss.end-point= +aliyun.oss.bucket= + +###### +## \u963F\u91CC\u4E91 - \u77ED\u4FE1 mns | sms +###### +sms.name=\u5BCC\u8302\u79D1\u6280\u6709\u9650\u516C\u53F8 +sms.bid=46565 +sms.account=15626593768 +sms.secret=7305150347587283553aa8898e7dbf20 +sms.publick-key=classpath://sms.key + +###### +## \u5FAE\u4FE1 +###### +wechat.mp.app-id= +wechat.mp.secret= +wechat.mp.token= +wechat.mp.aesKey= +wechat.mp.mch-id= +wechat.mp.mch-key= +wechat.mp.key-path= +###### +## \u767E\u5EA6 +###### +baidu.lbs.ak=UU7tWzU6kz4UesVqXnmOSWsFGkUQrRZs diff --git a/fumao-app/src/main/resources/banner.txt b/fumao-app/src/main/resources/banner.txt new file mode 100644 index 0000000..7fd7ac8 --- /dev/null +++ b/fumao-app/src/main/resources/banner.txt @@ -0,0 +1,17 @@ + +TTTTTTTTTTTTTTTTTTTTTTT kkkkkkkk kkkkkkkk +T:::::::::::::::::::::T k::::::k k::::::k +T:::::::::::::::::::::T k::::::k k::::::k +T:::::TT:::::::TT:::::T k::::::k k::::::k +TTTTTT T:::::T TTTTTT k:::::k kkkkkkk k:::::k kkkkkkk + T:::::T k:::::k k:::::k k:::::k k:::::k + T:::::T k:::::k k:::::k k:::::k k:::::k + T:::::T k:::::k k:::::k k:::::k k:::::k + T:::::T k::::::k:::::k k::::::k:::::k + T:::::T k:::::::::::k k:::::::::::k + T:::::T k:::::::::::k k:::::::::::k + T:::::T k::::::k:::::k k::::::k:::::k + TT:::::::TT k::::::k k:::::k k::::::k k:::::k + T:::::::::T k::::::k k:::::k k::::::k k:::::k + T:::::::::T k::::::k k:::::k k::::::k k:::::k + TTTTTTTTTTT kkkkkkkk kkkkkkk kkkkkkkk kkkkkkk diff --git a/fumao-app/src/main/resources/config.json b/fumao-app/src/main/resources/config.json new file mode 100644 index 0000000..0e0dcd2 --- /dev/null +++ b/fumao-app/src/main/resources/config.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/fumao-app/src/main/resources/messages.properties b/fumao-app/src/main/resources/messages.properties new file mode 100644 index 0000000..e07f113 --- /dev/null +++ b/fumao-app/src/main/resources/messages.properties @@ -0,0 +1,13 @@ +000000=ok +000001=\u7CFB\u7EDF\u9519\u8BEF +000002=\u5C1A\u672A\u767B\u5F55 +000003=\u53C2\u6570\u9519\u8BEF +000004=\u7528\u6237\u540D\u6216\u5BC6\u7801\u9519\u8BEF +000005=\u5FAE\u4FE1\u9519\u8BEF +000006=\u6CA1\u6709\u6743\u9650\u8BBF\u95EE +000007=\u8BBF\u95EE\u9891\u7E41, {0} +000008=\u767E\u5EA6\u63A5\u53E3\u8FD4\u56DE\u9519\u8BEF + + +100000=\u5DF2\u5B58\u5728\u76F8\u540C\u7684\u624B\u673A\u53F7 +100001=\u4E0D\u80FD\u5220\u9664\u81EA\u5DF1 \ No newline at end of file diff --git a/fumao-app/src/main/resources/permission.json b/fumao-app/src/main/resources/permission.json new file mode 100644 index 0000000..7829aa6 --- /dev/null +++ b/fumao-app/src/main/resources/permission.json @@ -0,0 +1,8 @@ +[ + { + "name": "", + "url": "", + "method": "", + "order": 0 + } +] \ No newline at end of file diff --git a/fumao-app/src/main/resources/sms.key b/fumao-app/src/main/resources/sms.key new file mode 100644 index 0000000..c233012 --- /dev/null +++ b/fumao-app/src/main/resources/sms.key @@ -0,0 +1,13 @@ +-----BEGIN PUBLIC KEY----- +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvh8j/zagfxQdnSh5OIic +MzN+MuRuWQJPjgu4Gza4+gX3j5Ln2xNDBOTjpwyuLBjh/JcBd1cGO3lAaKCwcaix +smhTq56wVXXUMgDiAChu4ud8FSvRc8G8tdZAirKVAIi3NW+/pYgpWBs/0wnF8hz4 +8no4pyJHl9Jc1LH3VNIMz8vqzKUPc4ack4pFUXlcNj6C+sBlaurmI4/vwLqNxBGs +7/zyM7dv6oy3DSU/Y1qBArM1YPjfL2dNun8rmtPgJvlPwXqA7uoHPwQ2Ym3aUn59 +pkS7QI6IE8uuqNkfSte8BXLd2nIqPLFxLYLDmdll7eoyRblHcHqAYSj8stK6StC7 +DNryNKEjTEwbgf9trUI0uvF1pfgTy2gpclnY69FtD/m0+FvLyorMq+nmBqYMjka5 +K0txDQJPOa7gsi//uXd/cJW2SAXY9MSO1AfMi8Xq/YKRQzN9FW5iapskXFHca7uX +g5NhH7flr6DW+QInFlpoN6WIEAuDF1aj4O49Ikm3WxwhTqnvEkdSCfivpYQkp9Sh +4kQ/SQdxuT7VX+Nz6k+uMx2z4cySk33bHi0KoHbA9QFGg/54Qd0+eU4qZnd4mrgh +hH7/QQhL7Z9eF1U5UPrsHq2Vq3rEnN+tYQ26AuKeU8vzTxBrC/SxC6C/SMFt3f/Y +nuFh1UnNJZleZwyQt+ZdGO0CAwEAAQ== \ No newline at end of file diff --git a/fumao-common/pom.xml b/fumao-common/pom.xml new file mode 100644 index 0000000..ac9e261 --- /dev/null +++ b/fumao-common/pom.xml @@ -0,0 +1,243 @@ + + + + fumao + com.aki + 0.0.1-SNAPSHOT + + 4.0.0 + + fumao-common + + + + + javax.servlet + servlet-api + 2.5 + provided + + + com.github.penggle + kaptcha + 2.3.2 + + + + + com.squareup.okhttp3 + okhttp + 3.10.0 + + + + + + com.aliyun.mns + aliyun-sdk-mns + 1.1.8.4 + + + com.aliyun.oss + aliyun-sdk-oss + 2.6.1 + + + com.aliyun + aliyun-java-sdk-core + 3.2.3 + system + ${project.basedir}/src/main/lib/aliyun-java-sdk-core-3.2.2.jar + + + com.aliyun + aliyun-java-sdk-dysmsapi + 1.0.0 + system + ${project.basedir}/src/main/lib/aliyun-java-sdk-dysmsapi-1.0.0-SANPSHOT.jar + + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.security + spring-security-jwt + + + + + com.github.binarywang + weixin-java-mp + ${weixin.version} + + + com.github.binarywang + weixin-java-pay + ${weixin.version} + + + com.github.binarywang + weixin-java-miniapp + ${weixin.version} + + + + + io.springfox + springfox-swagger-ui + + + io.springfox + springfox-swagger2 + + + + + org.projectlombok + lombok + + + com.alibaba + fastjson + 1.2.33 + + + org.redisson + redisson + 3.5.7 + + + + + io.jsonwebtoken + jjwt + ${jjwt.version} + + + + + org.apache.commons + commons-lang3 + 3.4 + + + commons-codec + commons-codec + 1.10 + + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 1.3.0 + + + com.github.pagehelper + pagehelper-spring-boot-starter + 1.1.2 + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.zaxxer + HikariCP + + + io.dropwizard.metrics + metrics-core + true + + + mysql + mysql-connector-java + + + com.h2database + h2 + + + org.hibernate + hibernate-validator + + + + + com.fasterxml.jackson.core + jackson-core + + + + com.fasterxml.jackson.core + jackson-annotations + + + + com.fasterxml.jackson.core + jackson-databind + + + + + org.springframework.data + spring-data-redis + + + org.springframework.boot + spring-boot-starter-redis + 1.4.7.RELEASE + + + + + + + + + + + + + + + + org.apache.poi + poi + 3.17 + + + org.apache.poi + poi-ooxml + 3.17 + + + + + joda-time + joda-time + 2.9.9 + + + + + com.deepoove + poi-tl + 1.2.0 + + + + org.springframework.boot + spring-boot-starter-test + test + + + \ No newline at end of file diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/BaseAop.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/BaseAop.java new file mode 100644 index 0000000..7faa38e --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/BaseAop.java @@ -0,0 +1,49 @@ +package com.chilunyc.fumao.common.aop; + +import javassist.*; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.core.LocalVariableTableParameterNameDiscoverer; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * + */ +public abstract class BaseAop { + + /** + * @param point + * @param clazz + * @param + * @return + */ + protected T getAnnotation(JoinPoint point, Class clazz) throws NoSuchMethodException { + MethodSignature signature = (MethodSignature) point.getSignature(); + Method method = point.getTarget().getClass().getMethod(signature.getName(), signature.getParameterTypes()); + return (T) method.getAnnotation(clazz); + } + + /** + * @param point + * @return + */ + protected String getMethodName(JoinPoint point) { + MethodSignature signature = (MethodSignature) point.getSignature(); + Method method = signature.getMethod(); + return method.getName(); + } + + protected Map getArgs(JoinPoint point) throws NotFoundException { + MethodSignature signature = (MethodSignature) point.getSignature(); + Map map = new HashMap<>(); + LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer(); + String[] parameterNames = u.getParameterNames(signature.getMethod()); + for (int i = 0; i < parameterNames.length; i++) { + map.put(parameterNames[i], point.getArgs()[i]);//paramNames即参数名 + } + return map; + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/cache/CacheAop.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/cache/CacheAop.java new file mode 100644 index 0000000..f07c314 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/cache/CacheAop.java @@ -0,0 +1,130 @@ +package com.chilunyc.fumao.common.aop.cache; + +import com.chilunyc.fumao.common.aop.BaseAop; +import com.chilunyc.fumao.common.util.SpelHelper; +import lombok.extern.log4j.Log4j; +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.lang.SerializationUtils; +import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.BoundValueOperations; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.stereotype.Component; + +import java.io.Serializable; +import java.util.Collections; +import java.util.Map; + +/** + * + */ +@Log4j +@Component +@Aspect +public class CacheAop extends BaseAop implements InitializingBean { + + @Autowired + private StringRedisTemplate redisTemplate; + + private DefaultRedisScript luaRemoveAllScript; + + /** + * 缓存cache + * + * @param proceedingJoinPoint + * @throws Throwable + */ + @Around("@annotation(com.chilunyc.fumao.common.aop.cache.Cacheable)") + Object cacheable(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { + try { + Cacheable annotation = getAnnotation(proceedingJoinPoint, Cacheable.class); + Map args = getArgs(proceedingJoinPoint); + String redisKey = annotation.value() + SpelHelper.exec(annotation.key(), args); + BoundValueOperations value = redisTemplate.boundValueOps(redisKey); + + // 有值 + String result = value.get(); + if (StringUtils.isNotBlank(result)) { + byte[] bytes = Hex.decodeHex(result.toCharArray()); + return SerializationUtils.deserialize(bytes); + } + // 没有值, 调用缓存 + else { + Object proceed = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs()); + if (proceed == null) { + return null; + } + //判断是否要存 + if (StringUtils.isNotBlank(annotation.exclude())) { + args.put("result", proceed); + Boolean isNotSave = SpelHelper.exec(annotation.exclude(), args); + if (isNotSave) { + return proceed; + } + } + //开始存 + byte[] serialize = SerializationUtils.serialize((Serializable) proceed); + String s = Hex.encodeHexString(serialize); + if (annotation.timeout() != -1L) { + value.set(s, annotation.timeout(), annotation.unit()); + } else { + value.set(s); + } + + // 放入一个list, 后面可以删除 + if (StringUtils.isNotBlank(annotation.value())) { + redisTemplate.boundListOps(annotation.value()).leftPush(redisKey); + } + return proceed; + } + } catch (Exception e) { + log.error(e); + return proceedingJoinPoint.proceed(); + } + } + + /** + * 清空cache + * + * @param joinPoint + * @throws Throwable + */ + @Before("@annotation(com.chilunyc.fumao.common.aop.cache.CacheEvict)") + void cacheEvict(JoinPoint joinPoint) throws Throwable { + CacheEvict annotation = getAnnotation(joinPoint, CacheEvict.class); + // 清空所有 + if (annotation.allEntries()) { + if (annotation.value().length > 0) { + for (String v : annotation.value()) { + redisTemplate.execute(luaRemoveAllScript, Collections.singletonList(v)); + } + } + } + // 清空单个 + else { + String v = annotation.value()[0]; + Map args = getArgs(joinPoint); + String redisKey = v + SpelHelper.exec(annotation.key(), args); + redisTemplate.delete(redisKey); + redisTemplate.boundListOps(v).remove(1, redisKey); + } + } + + @Override + public void afterPropertiesSet() throws Exception { + this.luaRemoveAllScript = new DefaultRedisScript<>(); + this.luaRemoveAllScript.setScriptText("local size = redis.call('llen', KEYS[1])\n" + + "local vs = redis.call('lrange', KEYS[1], 0, size)\n" + + "for x,y in ipairs(vs) do\n" + + " redis.call('del', y)\n" + + "end\n" + + "redis.call('ltrim', KEYS[1], size, -1)"); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/cache/CacheEvict.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/cache/CacheEvict.java new file mode 100644 index 0000000..977ecf0 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/cache/CacheEvict.java @@ -0,0 +1,19 @@ +package com.chilunyc.fumao.common.aop.cache; + +import java.lang.annotation.*; + +/** + * + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface CacheEvict { + + String[] value() default ""; + + String key() default ""; + + boolean allEntries() default false; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/cache/Cacheable.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/cache/Cacheable.java new file mode 100644 index 0000000..ac4ce69 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/cache/Cacheable.java @@ -0,0 +1,24 @@ +package com.chilunyc.fumao.common.aop.cache; + +import java.lang.annotation.*; +import java.util.concurrent.TimeUnit; + +/** + * + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface Cacheable { + + String value() default ""; + + String key() default ""; + + long timeout() default -1L; + + String exclude() default ""; + + TimeUnit unit() default TimeUnit.SECONDS; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/limit/Limit.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/limit/Limit.java new file mode 100644 index 0000000..5ac370f --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/limit/Limit.java @@ -0,0 +1,23 @@ +package com.chilunyc.fumao.common.aop.limit; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.concurrent.TimeUnit; + +/** + * + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Limit { + + String key() default ""; + + long timeout() default 5l; + + TimeUnit unit() default TimeUnit.SECONDS; + + String message() default "请忽重复提交"; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/limit/LimitAop.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/limit/LimitAop.java new file mode 100644 index 0000000..99a1746 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/limit/LimitAop.java @@ -0,0 +1,41 @@ +package com.chilunyc.fumao.common.aop.limit; + +import com.chilunyc.fumao.common.aop.BaseAop; +import com.chilunyc.fumao.common.exception.SystemException; +import com.chilunyc.fumao.common.util.SpelHelper; +import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * + */ +@Component +@Aspect +public class LimitAop extends BaseAop { + + @Autowired + private StringRedisTemplate redisTemplate; + + @Before("@annotation(com.chilunyc.fumao.common.aop.limit.Limit)") + void execute(JoinPoint joinPoint) throws Throwable { + Limit annotation = getAnnotation(joinPoint, Limit.class); + Map args = getArgs(joinPoint); + String redisKey = getMethodName(joinPoint) + (StringUtils.isBlank(annotation.key()) ? "" : SpelHelper.exec(annotation.key(), args)); + + // 没值, 缓存一下 + if (redisTemplate.opsForValue().setIfAbsent(redisKey, "v")) { + redisTemplate.expire(redisKey, annotation.timeout(), annotation.unit()); + } + // 有值, 所有有人提交过了, 出错 + else { + throw new SystemException("000007", new Object[]{annotation.message()}); + } + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/lock/Lock.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/lock/Lock.java new file mode 100644 index 0000000..d7347a3 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/lock/Lock.java @@ -0,0 +1,23 @@ +package com.chilunyc.fumao.common.aop.lock; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.concurrent.TimeUnit; + +/** + * + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Lock { + + String key() default ""; + + long timeout() default -1; + + TimeUnit unit() default TimeUnit.SECONDS; + + String message() default "请稍候重试"; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/lock/LockAop.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/lock/LockAop.java new file mode 100644 index 0000000..45a8acc --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/lock/LockAop.java @@ -0,0 +1,38 @@ +package com.chilunyc.fumao.common.aop.lock; + +import com.chilunyc.fumao.common.aop.BaseAop; +import com.chilunyc.fumao.common.util.SpelHelper; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * + */ +@Component +@Aspect +public class LockAop extends BaseAop { + + @Autowired + private RedissonClient redissonClient; + + @Around("@annotation(com.chilunyc.fumao.common.aop.lock.Lock)") + Object execute(ProceedingJoinPoint joinPoint) throws Throwable { + Lock annotation = getAnnotation(joinPoint, Lock.class); + Map args = getArgs(joinPoint); + String redisKey = getMethodName(joinPoint) + "_" + SpelHelper.exec(annotation.key(), args); + RLock lock = redissonClient.getLock(redisKey); + try { + lock.lock(); + return joinPoint.proceed(); + } finally { + lock.unlock(); + } + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/retry/Retry.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/retry/Retry.java new file mode 100644 index 0000000..5289099 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/retry/Retry.java @@ -0,0 +1,22 @@ +package com.chilunyc.fumao.common.aop.retry; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Retry { + + String scene() default ""; + + /** + * 最大次数 + * @return + */ + int maxTimes() default 3; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/retry/RetryAop.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/retry/RetryAop.java new file mode 100644 index 0000000..9d15cb6 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/aop/retry/RetryAop.java @@ -0,0 +1,32 @@ +package com.chilunyc.fumao.common.aop.retry; + +import com.chilunyc.fumao.common.aop.BaseAop; +import lombok.extern.log4j.Log4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; + +/** + * + */ +@Log4j +@Component +@Aspect +public class RetryAop extends BaseAop { + + @Around("@annotation(com.chilunyc.fumao.common.aop.retry.Retry)") + Object execute(ProceedingJoinPoint joinPoint) throws Throwable { + Retry annotation = getAnnotation(joinPoint, Retry.class); + int times = 0; + Object result = null; + while (times++ < annotation.maxTimes()) { + try { + result = joinPoint.proceed(); + } catch (Exception e) { + log.error(String.format("重试, 场景[%s], 参数[%s], 次数[%s] => 失败[%s]", annotation.scene(), joinPoint.getArgs(), times, e.getMessage())); + } + } + return result; + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/config/ApplicationProperty.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/config/ApplicationProperty.java new file mode 100644 index 0000000..9bf5503 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/config/ApplicationProperty.java @@ -0,0 +1,24 @@ +package com.chilunyc.fumao.common.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * + */ +@Data +@ConfigurationProperties(prefix = "app") +public class ApplicationProperty { + + private boolean test; + + private boolean role; + + private boolean auth; + + private boolean saveError; + + private String configPath; + + private String aesKey; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/config/CacheEnums.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/config/CacheEnums.java new file mode 100644 index 0000000..5aed003 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/config/CacheEnums.java @@ -0,0 +1,9 @@ +package com.chilunyc.fumao.common.config; + +/** + * + */ +public interface CacheEnums { + + String Permission = "Permission"; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/config/ConfigEnum.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/config/ConfigEnum.java new file mode 100644 index 0000000..eb1887a --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/config/ConfigEnum.java @@ -0,0 +1,8 @@ +package com.chilunyc.fumao.common.config; + + +/** + * + */ +public enum ConfigEnum { +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/config/ConfigRequest.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/config/ConfigRequest.java new file mode 100644 index 0000000..db2bbf0 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/config/ConfigRequest.java @@ -0,0 +1,14 @@ +package com.chilunyc.fumao.common.config; + +import lombok.Data; + +/** + * + */ +@Data +public class ConfigRequest { + + private ConfigEnum key; + + private String value; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/config/ConfigService.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/config/ConfigService.java new file mode 100644 index 0000000..3534238 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/config/ConfigService.java @@ -0,0 +1,46 @@ +package com.chilunyc.fumao.common.config; + +import com.alibaba.fastjson.JSON; +import lombok.extern.log4j.Log4j; +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.data.redis.core.BoundHashOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.io.InputStream; + +/** + * + */ +@Log4j +@Service +public class ConfigService implements InitializingBean { + + @Autowired + private RedisTemplate redisTemplate; + + @Autowired + private ApplicationProperty applicationProperty; + private BoundHashOperations ops; + + public void set(ConfigEnum key, Object v) { + this.ops.put(key.name(), v); + } + + public T get(ConfigEnum key) { + return (T) this.ops.get(key.name()); + } + + @Override + public void afterPropertiesSet() throws Exception { + this.ops = redisTemplate.boundHashOps(ConfigService.class.getName()); + if (this.ops.size() == 0) { + InputStream inputStream = new DefaultResourceLoader().getResource(applicationProperty.getConfigPath()).getInputStream(); + String configContent = IOUtils.toString(inputStream, "utf-8"); + this.ops.putAll(JSON.parseObject(configContent)); + } + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/config/RedissonConfig.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/config/RedissonConfig.java new file mode 100644 index 0000000..f7ddb0a --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/config/RedissonConfig.java @@ -0,0 +1,23 @@ +package com.chilunyc.fumao.common.config; + +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.config.Config; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class RedissonConfig { + + @Autowired + private RedisProperties redisProperties; + + @Bean + RedissonClient redissonClient() { + Config config = new Config(); + config.useSingleServer().setAddress(String.format("redis://%s:%s", redisProperties.getHost(), redisProperties.getPort())); + return Redisson.create(config); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/context/LoginUser.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/context/LoginUser.java new file mode 100644 index 0000000..fbf834f --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/context/LoginUser.java @@ -0,0 +1,42 @@ +package com.chilunyc.fumao.common.context; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtBuilder; + +/** + * + */ +public interface LoginUser { + + /** + * Id + * + * @return + */ + T getId(); + + /** + * 用户名 + * + * @return + */ + String getName(); + + + /** + * @return + */ + String[] toRoles(); + + /** + * + * @param claims + */ + void fromJwt(Claims claims); + + /** + * + * @param claims + */ + void toJwt(JwtBuilder claims); +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/context/Request.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/context/Request.java new file mode 100644 index 0000000..7e4f4b5 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/context/Request.java @@ -0,0 +1,77 @@ +package com.chilunyc.fumao.common.context; + +import com.chilunyc.fumao.common.util.jwt.JwtUtils; +import io.jsonwebtoken.Claims; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +/** + * + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Request { + + private JwtUtils.T jwtType; + + private Claims jwtValue; + + public String getIp() { + String ip = request.getHeader("x-real-ip"); + if (StringUtils.isBlank(ip)) { + return request.getRemoteAddr(); + } + return ip; + } + + public String getHost() { + return request.getServerName(); + } + + private String getPort() { + int port = request.getServerPort(); + return port == 80 ? "" : ":" + String.valueOf(port); + } + + private HttpServletRequest request; + + private LoginUser loginUser; + + public T getLoginUserId() { + LoginUser loginUser = getLoginUser(); + if (loginUser == null) { + return null; + } else { + return (T) loginUser.getId(); + } + } + + /** + * @return + */ + public String getSite() { + return String.format("%s://%s%s", StringUtils.contains(request.getProtocol(), "https") ? "https" : "http", getHost(), getPort()); + } + + /** + * @return + */ + public HttpSession getSession() { + return request.getSession(true); + } + + /** + * @return + */ + public String getJwt() { + return request.getHeader("token"); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/context/RequestHolder.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/context/RequestHolder.java new file mode 100644 index 0000000..8396ede --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/context/RequestHolder.java @@ -0,0 +1,20 @@ +package com.chilunyc.fumao.common.context; + +/** + * + */ +public class RequestHolder { + private static final ThreadLocal r = new ThreadLocal<>(); + + public static Request get() { + return r.get(); + } + + public static void set(Request request) { + r.set(request); + } + + public static void clean() { + r.remove(); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/enums/Comparing.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/enums/Comparing.java new file mode 100644 index 0000000..1317f87 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/enums/Comparing.java @@ -0,0 +1,10 @@ +package com.chilunyc.fumao.common.enums; + +/** + * 80347471@qq.com + */ +public enum Comparing { + Big, + Equal, + Small +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/enums/YesOrNo.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/enums/YesOrNo.java new file mode 100644 index 0000000..893a5b9 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/enums/YesOrNo.java @@ -0,0 +1,10 @@ +package com.chilunyc.fumao.common.enums; + +/** + * + */ +public enum YesOrNo { + Yes, + + No +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/exception/SystemException.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/exception/SystemException.java new file mode 100644 index 0000000..e6d9c20 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/exception/SystemException.java @@ -0,0 +1,48 @@ +package com.chilunyc.fumao.common.exception; + +import lombok.Data; + +/** + * + */ +@Data +public class SystemException extends RuntimeException { + + private String errorCode; + + private Object[] params; + + public SystemException() { + super(); + this.errorCode = "KK-000001"; + } + + public SystemException(String errorCode) { + super(); + this.errorCode = errorCode; + } + + public SystemException(String errorCode, Object... params) { + this.errorCode = errorCode; + this.params = params; + } + + public SystemException(String errorCode, Throwable cause) { + super(cause); + this.errorCode = errorCode; + } + + public SystemException(String errorCode, Object[] params, Throwable cause) { + super(cause); + this.errorCode = errorCode; + this.params = params; + } + +// public KKException(Throwable cause) { +// super(cause); +// } + +// public KKException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { +// super(message, cause, enableSuppression, writableStackTrace); +// } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/config/LBSConfig.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/config/LBSConfig.java new file mode 100644 index 0000000..12685ee --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/config/LBSConfig.java @@ -0,0 +1,12 @@ +package com.chilunyc.fumao.common.lbs.config; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * + */ +@Configuration +@EnableConfigurationProperties(LBSProperties.class) +public class LBSConfig { +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/config/LBSProperties.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/config/LBSProperties.java new file mode 100644 index 0000000..e2fd8bd --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/config/LBSProperties.java @@ -0,0 +1,14 @@ +package com.chilunyc.fumao.common.lbs.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * + */ +@Data +@ConfigurationProperties("baidu.lbs") +public class LBSProperties { + + private String ak; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/model/LBSAddress.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/model/LBSAddress.java new file mode 100644 index 0000000..ba86806 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/model/LBSAddress.java @@ -0,0 +1,20 @@ +package com.chilunyc.fumao.common.lbs.model; + +import lombok.Data; + +/** + * + */ +@Data +public class LBSAddress { + + private Double lat; + + private Double lng; + + private String province; + + private String city; + + private String county; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/model/LBSPoi.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/model/LBSPoi.java new file mode 100644 index 0000000..fc45752 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/model/LBSPoi.java @@ -0,0 +1,42 @@ +package com.chilunyc.fumao.common.lbs.model; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +/** + * Created by Tkk on 2018/7/24. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class LBSPoi { + + @Data + @NoArgsConstructor + public static class Location { + @JSONField(name = "lat") + private String lat; + + @JSONField(name = "lng") + private String lng; + } + + private Location location; + + @JSONField(name = "uid") + private String poi; + + private String province; + + private String city; + + private String address; + + private String name; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/request/LBSPoiRequest.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/request/LBSPoiRequest.java new file mode 100644 index 0000000..6740c0e --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/request/LBSPoiRequest.java @@ -0,0 +1,15 @@ +package com.chilunyc.fumao.common.lbs.request; + +import com.chilunyc.fumao.common.request.PageRequest; +import lombok.Data; + +/** + * Created by Tkk on 2018/7/24. + */ +@Data +public class LBSPoiRequest extends PageRequest { + + private String query; + + private String city; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/service/LBSService.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/service/LBSService.java new file mode 100644 index 0000000..8281b9b --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/lbs/service/LBSService.java @@ -0,0 +1,78 @@ +package com.chilunyc.fumao.common.lbs.service; + +import com.chilunyc.fumao.common.exception.SystemException; +import com.chilunyc.fumao.common.lbs.config.LBSProperties; +import com.chilunyc.fumao.common.lbs.model.LBSPoi; +import com.chilunyc.fumao.common.lbs.request.LBSPoiRequest; +import com.chilunyc.fumao.common.util.http.service.HttpClient; +import com.chilunyc.fumao.common.util.http.service.HttpParams; +import com.chilunyc.fumao.common.util.http.service.result.ResultExecute; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.log4j.Log4j; +import okhttp3.Request; +import okhttp3.Response; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.stereotype.Service; +import org.springframework.util.StopWatch; + +import java.util.ArrayList; +import java.util.List; + +/** + * + */ +@Log4j +@Service +public class LBSService implements ResultExecute { + + @Autowired + private HttpClient httpClient; + + @Autowired + private LBSProperties lbsProperties; + + private ObjectMapper objectMapper = new ObjectMapper(); + + /** + * @param request + * @return + */ + public Page findPoi(LBSPoiRequest request) { + HttpParams httpParams = HttpParams.get("http://api.map.baidu.com/place/v2/search"); + httpParams + .put("query", request.getQuery()) + .put("region", request.getCity()) + .put("page_size", request.getSize()) + .put("page_num", request.getPageI()) + .put("output", "json") + .put("ak", lbsProperties.getAk()); + String body = httpClient.execute(httpParams, this); + JSONObject object = JSON.parseObject(body); + JSONArray jsonArray = object.getJSONArray("results"); + int total = object.getIntValue("total"); + List pois = new ArrayList<>(jsonArray.size()); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + LBSPoi lbsPoi = jsonObject.toJavaObject(LBSPoi.class); + lbsPoi.setLocation(jsonObject.getJSONObject("location").toJavaObject(LBSPoi.Location.class)); + pois.add(lbsPoi); + } + return new PageImpl<>(pois, request.getPage(), total); + } + + @Override + public String toBody(Response response, Request request, StopWatch stopWatch) throws Exception { + String string = response.body().string(); + if (StringUtils.contains(string, "\"status\":0")) { + return string; + } + log.error(string); + throw new SystemException("000008"); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/log/model/Event.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/log/model/Event.java new file mode 100644 index 0000000..1ea5358 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/log/model/Event.java @@ -0,0 +1,64 @@ +package com.chilunyc.fumao.common.log.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.util.Date; + +/** + * + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "fumao_event_log", indexes = { + @Index(name = "event_log_operator", columnList = "operator"), + @Index(name = "event_log_targetId", columnList = "targetId"), + @Index(name = "event_log_type", columnList = "type"), + @Index(name = "event_log_target", columnList = "target"), +}) +public class Event { + + @Id + @GeneratedValue + private Long id; + + @Column(length = 1) + private EventTarget target; + + @Column(length = 1) + private EventType type; + + /** + * 操作人 + */ + @Column(length = 32) + private String operator; + + /** + * + */ + @Column(length = 32) + private String targetId; + + /** + * + */ + @Lob + private String content; + + /** + * + */ + private String ip; + + /** + * + */ + private Date createTime; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/log/model/EventTarget.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/log/model/EventTarget.java new file mode 100644 index 0000000..249b4cc --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/log/model/EventTarget.java @@ -0,0 +1,8 @@ +package com.chilunyc.fumao.common.log.model; + +/** + * + */ +public enum EventTarget { + System, Company, None +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/log/model/EventType.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/log/model/EventType.java new file mode 100644 index 0000000..702261f --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/log/model/EventType.java @@ -0,0 +1,12 @@ +package com.chilunyc.fumao.common.log.model; + +/** + * + */ +public enum EventType { + + Error, + + // 权限 + RoleEdit, RoleDelete, PermissionEdit, PermissionRemove, SendMsg, 编辑系统管理员, 删除系统管理员, 编辑集团, 删除集团, 编辑商场, 删除商场, 编辑商场楼层, 删除商场楼层, 编辑集团申请, 删除集团申请, 编辑商铺申请, 删除商铺申请, 编辑集团管理员, 删除集团管理员, 编辑商场管理员角色, 删除商场管理员角色, 编辑商场管理员, 删除商场管理员, +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/log/repository/EventMapper.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/log/repository/EventMapper.java new file mode 100644 index 0000000..6a06858 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/log/repository/EventMapper.java @@ -0,0 +1,16 @@ +package com.chilunyc.fumao.common.log.repository; + +import com.chilunyc.fumao.common.log.request.LogPageRequest; +import com.chilunyc.fumao.common.log.response.LogResponse; +import com.github.pagehelper.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.session.RowBounds; + +/** + * + */ +@Mapper +public interface EventMapper { + + Page page(LogPageRequest request, RowBounds rowBounds); +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/log/repository/EventRepository.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/log/repository/EventRepository.java new file mode 100644 index 0000000..8acd662 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/log/repository/EventRepository.java @@ -0,0 +1,12 @@ +package com.chilunyc.fumao.common.log.repository; + + +import com.chilunyc.fumao.common.log.model.Event; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** + * + */ +public interface EventRepository extends JpaRepository, JpaSpecificationExecutor { +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/log/request/LogPageRequest.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/log/request/LogPageRequest.java new file mode 100644 index 0000000..a2fdef2 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/log/request/LogPageRequest.java @@ -0,0 +1,21 @@ +package com.chilunyc.fumao.common.log.request; + +import com.chilunyc.fumao.common.request.PageRequest; +import lombok.Data; + +import java.util.Date; + +/** + * + */ +@Data +public class LogPageRequest extends PageRequest { + + private String eventType; + + private String eventTarget; + + private Date startTime; + + private Date endTime; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/log/response/LogResponse.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/log/response/LogResponse.java new file mode 100644 index 0000000..227fcd2 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/log/response/LogResponse.java @@ -0,0 +1,24 @@ +package com.chilunyc.fumao.common.log.response; + +import lombok.Data; + +import java.util.Date; + +/** + * + */ +@Data +public class LogResponse { + + private String name; + + private String eventType; + + private String eventTarget; + + private String content; + + private String ip; + + private Date createTime; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/log/service/EventService.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/log/service/EventService.java new file mode 100644 index 0000000..4cb0068 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/log/service/EventService.java @@ -0,0 +1,77 @@ +package com.chilunyc.fumao.common.log.service; + +import com.chilunyc.fumao.common.log.model.Event; +import com.chilunyc.fumao.common.log.model.EventTarget; +import com.chilunyc.fumao.common.log.model.EventType; +import com.chilunyc.fumao.common.log.repository.EventRepository; +import com.chilunyc.fumao.common.context.Request; +import com.alibaba.fastjson.JSON; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.Serializable; +import java.util.Date; + +/** + * + */ +@Log4j +@Service +@Transactional +@Async +public class EventService { + + @Autowired + private EventRepository eventRepository; + + + public void add(Request request, EventTarget target, EventType type, String targetId) { + add(request, target, type, targetId, null); + } + + public void add(Request request, EventType type, String targetId, Object content) { + add(request, EventTarget.None, type, targetId, content); + } + + public void add(Request request, EventType type, Object content) { + add(request, EventTarget.None, type, null, content); + } + + public void add(Request request, EventTarget target, EventType type) { + add(request, target, type, null, null); + } + + /** + * @param request + * @param target + * @param type + * @param targetId + * @param content + */ + public void add(Request request, EventTarget target, EventType type, Serializable targetId, Object content) { + String contentStr = ""; + if (content != null && !content.getClass().isAssignableFrom(String.class)) { + contentStr = JSON.toJSONString(content); + } else if (content != null) { + contentStr = content.toString(); + } + String operator = ""; + if (request != null && request.getLoginUser() != null) { + operator = request.getLoginUser().getId().toString(); + } + Event build = Event + .builder() + .target(target) + .ip(request == null ? "" : request.getIp()) + .type(type) + .operator(operator) + .targetId(targetId != null ? target.toString() : null) + .content(contentStr) + .createTime(new Date()) + .build(); + eventRepository.save(build); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/request/AssignsRequest.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/request/AssignsRequest.java new file mode 100644 index 0000000..e9208d2 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/request/AssignsRequest.java @@ -0,0 +1,20 @@ +package com.chilunyc.fumao.common.request; + +import lombok.Data; +import org.hibernate.validator.constraints.NotBlank; + +import javax.validation.constraints.Size; +import java.util.List; + +/** + * + */ +@Data +public class AssignsRequest { + + @Size(min = 0, message = "目标不存在") + private List id; + + @NotBlank(message = "分配数据为空") + private String targetId; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/request/ChangePwdRequest.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/request/ChangePwdRequest.java new file mode 100644 index 0000000..a5e19c5 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/request/ChangePwdRequest.java @@ -0,0 +1,15 @@ +package com.chilunyc.fumao.common.request; + +import com.chilunyc.fumao.common.sms.request.SmsCheckRequest; +import lombok.Data; +import org.hibernate.validator.constraints.NotBlank; + +/** + * + */ +@Data +public class ChangePwdRequest extends SmsCheckRequest { + + @NotBlank(message = "请输入密码") + private String password; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/request/IdsRequest.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/request/IdsRequest.java new file mode 100644 index 0000000..bc7dca1 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/request/IdsRequest.java @@ -0,0 +1,23 @@ +package com.chilunyc.fumao.common.request; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.List; + +/** + * + */ +@ApiModel +@Data +public class IdsRequest { + + @ApiModelProperty(value = "批量操作") + @NotNull(message = "编号不能为空") + @Size(min = 1, message = "编号不能为空") + private List ids; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/request/LoginRequest.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/request/LoginRequest.java new file mode 100644 index 0000000..511a232 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/request/LoginRequest.java @@ -0,0 +1,24 @@ +package com.chilunyc.fumao.common.request; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.hibernate.validator.constraints.NotBlank; + +/** + * + */ +@ApiModel +@Data +public class LoginRequest { + + @ApiModelProperty(value = "手机号") + @NotBlank(message = "请输入手机号") + private String mobile; + + @ApiModelProperty(value = "密码") + @NotBlank(message = "请输入密码") + private String password; + + +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/request/LoginRequestWithCaptcha.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/request/LoginRequestWithCaptcha.java new file mode 100644 index 0000000..1f02825 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/request/LoginRequestWithCaptcha.java @@ -0,0 +1,21 @@ +package com.chilunyc.fumao.common.request; + +import com.chilunyc.fumao.common.util.valid.Captcha; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.hibernate.validator.constraints.NotBlank; + +/** + * + */ +@ApiModel +@Data +public class LoginRequestWithCaptcha extends LoginRequest { + + @ApiModelProperty(value = "密码") + @Captcha + @NotBlank(message = "请输入验证码") + private String captcha; + +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/request/LoginRequestWithSMS.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/request/LoginRequestWithSMS.java new file mode 100644 index 0000000..c677841 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/request/LoginRequestWithSMS.java @@ -0,0 +1,19 @@ +package com.chilunyc.fumao.common.request; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.hibernate.validator.constraints.NotBlank; + +/** + * + */ +@ApiModel +@Data +public class LoginRequestWithSMS extends LoginRequest { + + @ApiModelProperty(value = "短信验证码") + @NotBlank(message = "请输入短信验证码") + private String code; + +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/request/PageRequest.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/request/PageRequest.java new file mode 100644 index 0000000..526c9a3 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/request/PageRequest.java @@ -0,0 +1,45 @@ +package com.chilunyc.fumao.common.request; + +import lombok.Data; + +import java.util.Date; + +/** + * + */ +@Data +public class PageRequest { + + private int size; + + private int page; + + private Date[] timeRange; + + public Date getStartTime(){ + return timeRange != null && timeRange.length == 2 ? timeRange[0] : null; + } + + public Date getEndTime(){ + return timeRange != null && timeRange.length == 2 ? timeRange[1] : null; + } + + /** + * @return + */ + public int getStart() { + return (page < 0 ? 0 : page) * getSize(); + } + + public int getPageI() { + return page < 0 ? 0 : page; + } + + public int getSize() { + return size <= 0 || size > 100 ? 10 : size; + } + + public org.springframework.data.domain.PageRequest getPage() { + return new org.springframework.data.domain.PageRequest(getPageI(), getSize()); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/response/JsonResponse.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/response/JsonResponse.java new file mode 100644 index 0000000..f4d1fe4 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/response/JsonResponse.java @@ -0,0 +1,78 @@ +package com.chilunyc.fumao.common.response; + +import com.alibaba.fastjson.JSON; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * + */ +@ApiModel +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class JsonResponse { + + @ApiModelProperty(value = "状态码 000000 正常, 000000 不正常") + private String result; + + @ApiModelProperty(value = "当result为 000000 获取这个值") + private T data; + + @ApiModelProperty(value = "当result不为 000000 获取这个值") + private String error; + + /** + * @param object + * @return + */ + public static JsonResponse success(T object) { + JsonResponse o = new JsonResponse<>(); + o.setData(object); + o.setResult("000000"); + return o; + } + + /** + * @return + */ + public static JsonResponse success() { + return success(""); + } + + /** + * @param message + * @return + */ + public static JsonResponse fail(String errorCode, String message) { + return JsonResponse + .builder() + .result(errorCode) + .error(message) + .build(); + } + + /** + * @return + */ + public static JsonResponse fail() { + return fail("000001", "系统错误"); + } + + /** + * @param message + * @return + */ + public static JsonResponse fail(String message) { + return fail("000001", message); + } + + public String toString() { + return JSON.toJSONString(this); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/response/KeyValue.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/response/KeyValue.java new file mode 100644 index 0000000..76f3b57 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/response/KeyValue.java @@ -0,0 +1,15 @@ +package com.chilunyc.fumao.common.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class KeyValue { + private String key; + private Object value; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/response/KeyValues.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/response/KeyValues.java new file mode 100644 index 0000000..3ebc46b --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/response/KeyValues.java @@ -0,0 +1,18 @@ +package com.chilunyc.fumao.common.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class KeyValues { + private String key; + + private List values; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/response/NodeResponse.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/response/NodeResponse.java new file mode 100644 index 0000000..5df4647 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/response/NodeResponse.java @@ -0,0 +1,24 @@ +package com.chilunyc.fumao.common.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class NodeResponse { + + private String label; + + private String value; + + private List children; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/shiro/AuthRoles.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/shiro/AuthRoles.java new file mode 100644 index 0000000..63de492 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/shiro/AuthRoles.java @@ -0,0 +1,25 @@ +package com.chilunyc.fumao.common.shiro; + +/** + * Created by Tkk on 2018/7/23. + */ +public interface AuthRoles { + + /** + * + */ + String SystemAdmin = "SystemAdmin"; + String SystemAdminExp = "hasAuthority('SystemAdmin')"; + + /** + * + */ + String CompanyAdmin = "CompanyAdmin"; + String CompanyAdminExp = "hasAuthority('CompanyAdmin')"; + + /** + * + */ + String MarketAdmin = "MarketAdmin"; + String MarketAdminExp = "hasAuthority('MarketAdmin')"; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/shiro/AuthUser.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/shiro/AuthUser.java new file mode 100644 index 0000000..9ba7632 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/shiro/AuthUser.java @@ -0,0 +1,72 @@ +package com.chilunyc.fumao.common.shiro; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Created by Tkk on 2018/7/23. + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AuthUser implements UserDetails { + + private Long id; + + private String username; + + private String password; + + private List authorities; + + public AuthUser setRole(String... roles) { + this.authorities = Stream.of(roles).map(SimpleGrantedAuthority::new).collect(Collectors.toList()); + return this; + } + + @Override + public Collection getAuthorities() { + return authorities; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/config/SmsConfig.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/config/SmsConfig.java new file mode 100644 index 0000000..75db87c --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/config/SmsConfig.java @@ -0,0 +1,17 @@ +package com.chilunyc.fumao.common.sms.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * + */ +@Configuration +@EnableConfigurationProperties(SmsProperties.class) +public class SmsConfig { + + @Autowired + private SmsProperties smsProperties; + +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/config/SmsProperties.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/config/SmsProperties.java new file mode 100644 index 0000000..0627d89 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/config/SmsProperties.java @@ -0,0 +1,37 @@ +package com.chilunyc.fumao.common.sms.config; + +import lombok.Data; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.core.io.DefaultResourceLoader; + +import java.io.InputStream; + +/** + * + */ +@Data +@ConfigurationProperties("sms") +public class SmsProperties implements InitializingBean { + + private String name; + + private String bid; + + private String account; + + private String secret; + + private String publicKey; + + @Override + public void afterPropertiesSet() throws Exception { + if (StringUtils.isNotBlank(publicKey)) { + InputStream inputStream = new DefaultResourceLoader().getResource(publicKey).getInputStream(); + publicKey = IOUtils.toString(inputStream, "utf-8"); + IOUtils.closeQuietly(inputStream); + } + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/model/Sms.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/model/Sms.java new file mode 100644 index 0000000..9ebb259 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/model/Sms.java @@ -0,0 +1,69 @@ +package com.chilunyc.fumao.common.sms.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.util.Date; + +/** + * + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "fumao_sms") +public class Sms { + + @Id + @Column(columnDefinition = "bigint(64)") + private String id; + + /** + * 手机号 + */ + @Column(length = 11) + private String mobile; + + /** + * 发送类型 + */ + @Column(length = 16) + @Enumerated(EnumType.STRING) + private SmsType type; + + /** + * 验证次数 + */ + @Column(length = 2) + private Integer checkCount; + + /** + * 内容 + */ + private String content; + + /** + * 备注 + */ + private String mark; + + /** + * 过期时间 + */ + private Date expiredTime; + + /** + * + */ + private Boolean isCheck; + + /** + * + */ + private Date createTime; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/model/SmsType.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/model/SmsType.java new file mode 100644 index 0000000..c22c2b5 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/model/SmsType.java @@ -0,0 +1,27 @@ +package com.chilunyc.fumao.common.sms.model; + +/** + * + */ +public enum SmsType { + + /** + * 注册 + */ + CustomerRegister(""), + + /** + * 找回密码 + */ + CustomerFindPwd(""); + + private String tpl; + + SmsType(String tpl) { + this.tpl = tpl; + } + + public String getTemplate() { + return tpl; + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/repository/SmsRepository.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/repository/SmsRepository.java new file mode 100644 index 0000000..ea399bf --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/repository/SmsRepository.java @@ -0,0 +1,38 @@ +package com.chilunyc.fumao.common.sms.repository; + +import com.chilunyc.fumao.common.sms.model.Sms; +import com.chilunyc.fumao.common.sms.model.SmsType; +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.transaction.annotation.Transactional; + +/** + * + */ +public interface SmsRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 最后最后一次发现的短信 + * + * @param mobile + * @return + */ + Sms findFirstByMobileOrderByCreateTimeDesc(String mobile); + + /** + * 设置sms为禁用 + * + * @param mobile + * @param type + * @param mark + * @return + */ + @Transactional + @Modifying + @Query( + "Update Sms s set s.isCheck = true, s.mark = ?3 Where s.mobile = ?1 and s.type = ?2 and s.isCheck = false" + ) + int disabled(String mobile, SmsType type, String mark); +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/request/SmsCheckRequest.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/request/SmsCheckRequest.java new file mode 100644 index 0000000..5f48f54 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/request/SmsCheckRequest.java @@ -0,0 +1,40 @@ +package com.chilunyc.fumao.common.sms.request; + +import com.chilunyc.fumao.common.sms.model.SmsType; +import com.chilunyc.fumao.common.util.jpa.query.QueryItem; +import com.chilunyc.fumao.common.util.jpa.query.QueryType; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.hibernate.validator.constraints.NotBlank; +import org.springframework.data.jpa.domain.Specification; + +import javax.persistence.criteria.Predicate; +import javax.validation.constraints.Pattern; +import java.util.ArrayList; +import java.util.List; + +/** + * + */ +@ApiModel +@Data +public class SmsCheckRequest { + + @ApiModelProperty(value = "手机号") + @NotBlank(message = "请输入手机号") + @Pattern(regexp = "1[\\d]{10}", message = "请输入正确的手机号") + @QueryItem(type = QueryType.equal) + private String mobile; + + @ApiModelProperty(value = "短信验证码") + @NotBlank(message = "请输入短信验证码") + private String code; + + @ApiModelProperty(hidden = true) + @QueryItem(type = QueryType.equal) + private SmsType type; + + @QueryItem(type = QueryType.equal) + private boolean isCheck = false; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/request/SmsSendRequest.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/request/SmsSendRequest.java new file mode 100644 index 0000000..d53ede9 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/request/SmsSendRequest.java @@ -0,0 +1,34 @@ +package com.chilunyc.fumao.common.sms.request; + +import com.chilunyc.fumao.common.sms.model.SmsType; +import com.chilunyc.fumao.common.util.valid.Captcha; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.hibernate.validator.constraints.NotBlank; + +import javax.validation.constraints.Pattern; + +/** + * + */ +@ApiModel +@Data +public class SmsSendRequest { + + @ApiModelProperty(value = "手机号") + @NotBlank(message = "请输入手机号") + @Pattern(regexp = "1[34578]\\d{9}", message = "手机号不正确") + private String mobile; + + @ApiModelProperty(value = "图形验证码") + @NotBlank(message = "请输入图形验证码") + @Captcha + private String captcha; + + @ApiModelProperty(hidden = true) + private SmsType type; + + @ApiModelProperty(hidden = true) + private String content; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/service/SmsService.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/service/SmsService.java new file mode 100644 index 0000000..75fa8d9 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/sms/service/SmsService.java @@ -0,0 +1,116 @@ +package com.chilunyc.fumao.common.sms.service; + +import com.chilunyc.fumao.common.context.RequestHolder; +import com.chilunyc.fumao.common.exception.SystemException; +import com.chilunyc.fumao.common.log.model.EventTarget; +import com.chilunyc.fumao.common.log.model.EventType; +import com.chilunyc.fumao.common.log.service.EventService; +import com.chilunyc.fumao.common.sms.config.SmsProperties; +import com.chilunyc.fumao.common.sms.model.Sms; +import com.chilunyc.fumao.common.sms.repository.SmsRepository; +import com.chilunyc.fumao.common.sms.request.SmsCheckRequest; +import com.chilunyc.fumao.common.sms.request.SmsSendRequest; +import com.chilunyc.fumao.common.util.jpa.query.QueryBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.concurrent.TimeUnit; + +/** + * + */ +@Service +@Transactional +public class SmsService { + + @Autowired + private SmsRepository smsRepository; + + @Autowired + private SmsProperties smsProperties; + + @Autowired + private EventService eventService; + + /** + * @param request + */ + @Transactional + public void send(SmsSendRequest request) { + //1. 取最后一次发送的短信 + Sms last = smsRepository.findFirstByMobileOrderByCreateTimeDesc(request.getMobile()); + if (last != null + && TimeUnit.SECONDS.convert(new Date().getTime() - last.getCreateTime().getTime(), TimeUnit.MILLISECONDS) < 60) { + throw new SystemException("300010"); + } + +// //2. 发送短信 +// Map map = MapBuilder +// .builder() +// .put("code", request.getContent()) +// .put("product", smsProperties.getSignName()) +// .getMap(); +// JsonResponse msgId = aliyunSender.send(request.getType().getTemplate(), request.getMobile(), map); +// if (StringUtils.isNotBlank(msgId.getError())) { +// throw new SystemException("300011", new Object[]{msgId.getError()}); +// } + + //3. 把所有该手机的可用的sms全部设置为不可用 + smsRepository.disabled(request.getMobile(), request.getType(), "再次发送短信"); + + //3. 存储 + Sms sms = Sms + .builder() + .type(request.getType()) + .isCheck(false) + .mobile(request.getMobile()) + .content(request.getContent()) + .build(); +// sms.setId(msgId.getData().toString()); + sms.setCheckCount(0); + sms.setCreateTime(new Date()); + sms.setExpiredTime(new Date(sms.getCreateTime().getTime() + 5 * 1000 * 60)); + smsRepository.save(sms); + eventService.add(RequestHolder.get(), EventTarget.None, EventType.SendMsg, request.getMobile()); + } + + /** + * @param request + */ + @Transactional(noRollbackFor = Exception.class) + public void check(SmsCheckRequest request) { + Sms one = smsRepository.findOne(QueryBuilder.build(request)); + if (one == null || (one != null && one.getIsCheck())) { + throw new SystemException("300012"); + } + // 过期 + else if (one.getExpiredTime().before(new Date())) { + one.setIsCheck(true); + one.setMark("验证时效"); + smsRepository.save(one); + throw new SystemException("300012"); + } + // 验证通过 + else if (StringUtils.equalsIgnoreCase(one.getContent(), request.getCode())) { + one.setIsCheck(true); + one.setMark("校验成功"); + smsRepository.save(one); + } + // 次数过多 + else if (one.getCheckCount() > 2) { + one.setIsCheck(true); + one.setMark("尝试次数过多"); + smsRepository.save(one); + throw new SystemException("300012"); + } + // 验证错误 + else { + one.setCheckCount(one.getCheckCount() + 1); + smsRepository.save(one); + throw new SystemException("300012"); + } + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/upload/config/UploadConfig.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/upload/config/UploadConfig.java new file mode 100644 index 0000000..b72d2f9 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/upload/config/UploadConfig.java @@ -0,0 +1,30 @@ +package com.chilunyc.fumao.common.upload.config; + +import com.aliyun.oss.OSSClient; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * + */ +@Configuration +@ConditionalOnProperty(name = "aliyun.oss.access-id") +@EnableConfigurationProperties(UploadProperties.class) +public class UploadConfig { + + @Autowired + private UploadProperties uploadProperties; + + @Bean + OSSClient ossClient() { + OSSClient client = null; + if (StringUtils.isNotBlank(uploadProperties.getAccessId())) { + client = new OSSClient(uploadProperties.getHost(), uploadProperties.getAccessId(), uploadProperties.getAccessKey()); + } + return client; + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/upload/config/UploadProperties.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/upload/config/UploadProperties.java new file mode 100644 index 0000000..7195a9e --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/upload/config/UploadProperties.java @@ -0,0 +1,25 @@ +package com.chilunyc.fumao.common.upload.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * + */ +@Data +@ConfigurationProperties("aliyun.oss") +public class UploadProperties { + + private String accessId; + + private String accessKey; + + private String endPoint; + + private String bucket; + + + public String getHost() { + return String.format("https://%s.%s", bucket, endPoint); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/upload/request/UploadRequest.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/upload/request/UploadRequest.java new file mode 100644 index 0000000..cd6aa6a --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/upload/request/UploadRequest.java @@ -0,0 +1,16 @@ +package com.chilunyc.fumao.common.upload.request; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * + */ +@ApiModel +@Data +public class UploadRequest { + + @ApiModelProperty(hidden = true) + private String dir; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/upload/response/UploadResponse.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/upload/response/UploadResponse.java new file mode 100644 index 0000000..580d0d4 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/upload/response/UploadResponse.java @@ -0,0 +1,30 @@ +package com.chilunyc.fumao.common.upload.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class UploadResponse { + + private String OSSAccessKeyId; + + private String policy; + + private String signature; + + private String dir; + + private String host; + + private String expire; + + private String key; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/upload/service/UploadService.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/upload/service/UploadService.java new file mode 100644 index 0000000..7e5c9e0 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/upload/service/UploadService.java @@ -0,0 +1,59 @@ +package com.chilunyc.fumao.common.upload.service; + +import com.chilunyc.fumao.common.exception.SystemException; +import com.chilunyc.fumao.common.upload.config.UploadProperties; +import com.chilunyc.fumao.common.upload.response.UploadResponse; +import com.aliyun.oss.OSSClient; +import com.aliyun.oss.common.utils.BinaryUtil; +import com.aliyun.oss.model.PolicyConditions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.UUID; + +/** + * + */ +@Service +@Transactional +public class UploadService { + + private Logger logger = LoggerFactory.getLogger(UploadService.class); + + @Autowired + private UploadProperties uploadProperties; + + @Autowired + private OSSClient client; + + public UploadResponse getAuth() { + try { + long expireTime = 30; + long expireEndTime = System.currentTimeMillis() + expireTime * 1000; + Date expiration = new Date(expireEndTime); + PolicyConditions policyConds = new PolicyConditions(); + policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000); + String postPolicy = client.generatePostPolicy(expiration, policyConds); + byte[] binaryData = postPolicy.getBytes("utf-8"); + String encodedPolicy = BinaryUtil.toBase64String(binaryData); + String postSignature = client.calculatePostSignature(postPolicy); + + return UploadResponse + .builder() + .key(UUID.randomUUID().toString().replaceAll("-", "")) + .OSSAccessKeyId(uploadProperties.getAccessId()) + .policy(encodedPolicy) + .signature(postSignature) + .host(uploadProperties.getHost()) + .expire(String.valueOf(expireEndTime / 1000)) + .build(); + } catch (Exception e) { + logger.error(e.getMessage(), e); + throw new SystemException("创建上传凭证失败"); + } + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/BeanHelper.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/BeanHelper.java new file mode 100644 index 0000000..9202c5d --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/BeanHelper.java @@ -0,0 +1,45 @@ +package com.chilunyc.fumao.common.util; + +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeanWrapper; +import org.springframework.beans.BeanWrapperImpl; + +import java.util.HashSet; +import java.util.Set; + +/** + * + */ +public class BeanHelper { + + /** + * 主要过滤 null 值 + * + * @param src + * @param target + */ + public static void copyProperties(Object src, Object target) { + BeanUtils.copyProperties(target, src, getNullPropertyNames(target)); + } + + /** + * @param source + * @return + */ + public static String[] getNullPropertyNames(Object source) { + final BeanWrapper src = new BeanWrapperImpl(source); + java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors(); + + Set emptyNames = new HashSet(); + for (java.beans.PropertyDescriptor pd : pds) { + if (pd.getWriteMethod() == null) { + continue; + } + Object srcValue = src.getPropertyValue(pd.getName()); + if (srcValue == null) emptyNames.add(pd.getName()); + } + String[] result = new String[emptyNames.size()]; + return emptyNames.toArray(result); + } + +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/CountHelper.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/CountHelper.java new file mode 100644 index 0000000..b158dfa --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/CountHelper.java @@ -0,0 +1,77 @@ +package com.chilunyc.fumao.common.util; + +import com.chilunyc.fumao.common.enums.Comparing; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.BoundValueOperations; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.concurrent.TimeUnit; + +/** + * + */ +@Component +public class CountHelper { + + @Autowired + private StringRedisTemplate redisTemplate; + + /** + * 小于则加1 + * 大于 + * + * @param key + * @param number + * @param expire + * @return + */ + public boolean isLessAndIncreament(String key, int number, int expire) { + if (this.compare(key, number).equals(Comparing.Small)) { + this.increament(key, expire); + return true; + } else { + return false; + } + } + + /** + * @param key + * @param number + * @return + */ + public Comparing compare(String key, int number) { + int count = this.count(key); + if (count == number) { + return Comparing.Equal; + } else if (count > number) { + return Comparing.Big; + } else { + return Comparing.Small; + } + } + + public int count(String key) { + String s = get(key); + if (StringUtils.isBlank(s)) { + return 0; + } else { + return Integer.parseInt(s); + } + } + + public void increament(String key, int expire) { + BoundValueOperations ops = redisTemplate.boundValueOps(key); + ops.increment(1); + ops.expire(expire, TimeUnit.SECONDS); + } + + public void delete(String key) { + redisTemplate.delete(key); + } + + public String get(String key) { + return redisTemplate.boundValueOps(key).get(); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/CovertHelper.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/CovertHelper.java new file mode 100644 index 0000000..d033639 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/CovertHelper.java @@ -0,0 +1,54 @@ +package com.chilunyc.fumao.common.util; + +import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.commons.lang3.time.DateUtils; + +import java.math.BigDecimal; +import java.text.ParseException; +import java.util.Date; +import java.util.regex.Pattern; + +/** + * 80347471@qq.com + */ +public class CovertHelper { + + private static String dateTimeRegexp = "\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}"; + private static String dateTimeFormat = "yyyy-MM-dd HH:mm:ss"; + private static String dateRegexp = "\\d{4}-\\d{2}-\\d{2}"; + private static String dateFormat = "yyyy-MM-dd"; + + public static Object stringTo(String src, Class toClass) { + if (toClass.isAssignableFrom(String.class)) { + return src; + } + // + else if (toClass.isAssignableFrom(Integer.class) || toClass.isAssignableFrom(int.class)) { + return Integer.parseInt(src); + } + // + else if (toClass.isAssignableFrom(Float.class) || toClass.isAssignableFrom(float.class)) { + return Float.parseFloat(src); + } + // + else if (toClass.isAssignableFrom(Double.class) || toClass.isAssignableFrom(double.class)) { + return Double.parseDouble(src); + } + // + else if (toClass.isAssignableFrom(BigDecimal.class)) { + return new BigDecimal(src); + } + // + else if (toClass.isAssignableFrom(Date.class)) { + try { + return DateUtils.parseDate(src, dateTimeFormat, dateFormat); + } catch (ParseException e) { + throw new UnsupportedOperationException(String.format("src[%s] can not format to Date", src), e); + } + } + // + else { + throw new UnsupportedOperationException(String.format("src[%s] => class[%s]", src, toClass)); + } + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/CryptoHelper.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/CryptoHelper.java new file mode 100644 index 0000000..8c1998d --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/CryptoHelper.java @@ -0,0 +1,50 @@ +package com.chilunyc.fumao.common.util; + +import org.apache.commons.codec.binary.Base64; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import java.security.MessageDigest; + +/** + * 80347471@qq.com + */ +public class CryptoHelper { + + // 加密算法 + private static final String ALG = "AES"; + // 字符编码 + private static final String ENC = "UTF-8"; + // 密钥正规化算法 + private static final String SEC_NORMALIZE_ALG = "MD5"; + + // 加密 + public static String aesEncrypt(String secret, String data) throws Exception { + MessageDigest dig = MessageDigest.getInstance(SEC_NORMALIZE_ALG); + byte[] key = dig.digest(secret.getBytes(ENC)); + SecretKeySpec secKey = new SecretKeySpec(key, ALG); + + Cipher aesCipher = Cipher.getInstance(ALG); + byte[] byteText = data.getBytes(ENC); + + aesCipher.init(Cipher.ENCRYPT_MODE, secKey); + byte[] byteCipherText = aesCipher.doFinal(byteText); + + Base64 base64 = new Base64(); + return new String(base64.encode(byteCipherText), ENC); + } + + // 解密 + public static String aesDecrypt(String secret, String ciphertext) throws Exception { + MessageDigest dig = MessageDigest.getInstance(SEC_NORMALIZE_ALG); + byte[] key = dig.digest(secret.getBytes(ENC)); + SecretKeySpec secKey = new SecretKeySpec(key, ALG); + + Cipher aesCipher = Cipher.getInstance(ALG); + aesCipher.init(Cipher.DECRYPT_MODE, secKey); + Base64 base64 = new Base64(); + byte[] cipherbytes = base64.decode(ciphertext.getBytes()); + byte[] bytePlainText = aesCipher.doFinal(cipherbytes); + return new String(bytePlainText, ENC); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/DateHelper.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/DateHelper.java new file mode 100644 index 0000000..cf7e77c --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/DateHelper.java @@ -0,0 +1,28 @@ +package com.chilunyc.fumao.common.util; + +import java.util.Calendar; +import java.util.Date; + +/** + * + */ +public class DateHelper { + + /** + * + * @param date + * @param date1 + * @param date2 + * @return + */ + public static boolean isSame(Date date, Date date1, int date2) { + if (date == null) { + return true; + } + Calendar c1 = Calendar.getInstance(); + Calendar c2 = Calendar.getInstance(); + c1.setTime(date); + c2.setTime(date1); + return c1.get(date2) == c2.get(date2); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/DateRangeHelper.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/DateRangeHelper.java new file mode 100644 index 0000000..b5c4ef8 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/DateRangeHelper.java @@ -0,0 +1,116 @@ +package com.chilunyc.fumao.common.util; + +import com.chilunyc.fumao.common.exception.SystemException; +import org.joda.time.DateTime; + +import java.util.Calendar; +import java.util.Date; + +/** + * + */ +public class DateRangeHelper { + + public static void main(String[] args) { + Date[] dates = DateRangeHelper.yearRange(); + System.out.println(dates[0] + " => " + dates[1]); + } + + /** + * 昨天 0 点 - 23:59:59 + * + * @return + */ + public static Date[] yesterdayRange() { + DateTime start = DateTime.now().withTimeAtStartOfDay(); + DateTime end = start.plusDays(1).minusSeconds(1); + return new Date[]{ + start.toDate(), + end.toDate() + }; + } + + /** + * 昨天 0 点 - 23:59:59 + * + * @return + */ + public static Date[] todayRange() { + DateTime start = DateTime.now().withTimeAtStartOfDay(); + return new Date[]{ + start.toDate(), + new Date() + }; + } + + /** + * 近7天 + * + * @return + */ + public static Date[] weekRange() { + DateTime end = DateTime.now(); + DateTime start = end.minusDays(7).withTimeAtStartOfDay(); + return new Date[]{ + start.toDate(), + end.toDate() + }; + } + + /** + * 近30天 + * + * @return + */ + public static Date[] monthRange() { + DateTime end = DateTime.now(); + DateTime start = end.minusDays(31).withTimeAtStartOfDay(); + return new Date[]{ + start.toDate(), + end.toDate() + }; + } + + /** + * 近1年 + * + * @return + */ + public static Date[] yearRange(Date startDate, Date endDate) { + if (startDate == null) { + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.MONTH, 0); + startDate = calendar.getTime(); + } + if (endDate != null && endDate.before(startDate)) { + throw new SystemException("300016"); + } + if (endDate == null) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(startDate); + calendar.add(Calendar.YEAR, 1); + endDate = calendar.getTime(); + } + return new Date[]{startDate, endDate}; + } + + + public static Date[] yearRange() { + DateTime end = DateTime.now(); + DateTime start = end.minusYears(1).withTimeAtStartOfDay(); + return new Date[]{ + start.toDate(), + end.toDate() + }; + + } + + public static Date[] yearRange(Integer year) { + DateTime end = DateTime.now(); + DateTime start = end.minusYears(year == null ? 1 : year).withTimeAtStartOfDay(); + return new Date[]{ + start.toDate(), + end.toDate() + }; + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/MapBuilder.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/MapBuilder.java new file mode 100644 index 0000000..9906158 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/MapBuilder.java @@ -0,0 +1,25 @@ +package com.chilunyc.fumao.common.util; + +import java.util.HashMap; +import java.util.Map; + +/** + * + */ +public class MapBuilder { + + private Map r = new HashMap<>(); + + public MapBuilder put(String k, Object v) { + r.put(k, v); + return this; + } + + public Map getMap() { + return this.r; + } + + public static MapBuilder builder() { + return new MapBuilder(); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/MathHelper.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/MathHelper.java new file mode 100644 index 0000000..10baff4 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/MathHelper.java @@ -0,0 +1,17 @@ +package com.chilunyc.fumao.common.util; + +import java.math.BigDecimal; + +/** + * + */ +public class MathHelper { + + public static double toFixed(Double value, int size) { + return BigDecimal.valueOf(value == null ? 0 : value).setScale(size, BigDecimal.ROUND_HALF_UP).doubleValue(); + } + + public static double toFixed(Double value){ + return toFixed(value, 2); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/SpelHelper.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/SpelHelper.java new file mode 100644 index 0000000..1c45221 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/SpelHelper.java @@ -0,0 +1,37 @@ +package com.chilunyc.fumao.common.util; + +import org.springframework.expression.Expression; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + */ +public class SpelHelper { + + private static ConcurrentHashMap m = new ConcurrentHashMap<>(); + + /** + * 动态执行 + * + * @param exp + * @param values + * @param + * @return + */ + public static T exec(String exp, Map values) { + Expression expression; + if (m.contains(exp)) { + expression = m.get(exp); + } else { + expression = new SpelExpressionParser().parseExpression(exp); + m.put(exp, expression); + } + StandardEvaluationContext context = new StandardEvaluationContext(); + context.setVariables(values); + return (T) expression.getValue(context); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/SpringHelper.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/SpringHelper.java new file mode 100644 index 0000000..7214212 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/SpringHelper.java @@ -0,0 +1,24 @@ +package com.chilunyc.fumao.common.util; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * + */ +@Component +public class SpringHelper implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + SpringHelper.applicationContext = applicationContext; + } + + public static T getBean(Class clazz) { + return applicationContext.getBean(clazz); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/StreamHelper.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/StreamHelper.java new file mode 100644 index 0000000..621b25f --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/StreamHelper.java @@ -0,0 +1,40 @@ +package com.chilunyc.fumao.common.util; + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * + */ +public class StreamHelper { + + /** + * 按某个字段去重 + * @param keyExtractor + * @param + * @return + */ + public static Predicate distinctByKey(Function keyExtractor) { + Map seen = new ConcurrentHashMap<>(); + return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; + } + + /** + * + * @param els + * @param action + * @param + */ + public static void foreach(Iterable els, BiConsumer action) { + Objects.requireNonNull(els); + Objects.requireNonNull(action); + int index = 0; + for (T el : els) { + action.accept(index++, el); + } + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/ExcelEntityDescription.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/ExcelEntityDescription.java new file mode 100644 index 0000000..acd32f5 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/ExcelEntityDescription.java @@ -0,0 +1,106 @@ +package com.chilunyc.fumao.common.util.excel; + +import com.chilunyc.fumao.common.util.excel.column.ExcelColumn; +import com.chilunyc.fumao.common.util.excel.row.ExcelRow; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.springframework.util.ReflectionUtils; + +import java.lang.reflect.Field; +import java.util.Map; +import java.util.TreeMap; + +/** + * 80347471@qq.com + */ +public class ExcelEntityDescription { + + private Class clazz; + + private ExcelRow excelRow; + + private final Map indexColumnMap = new TreeMap<>(); + + public ExcelEntityDescription(Class clazz) { + this.clazz = clazz; + this.analysis(); + } + + public T read(Row row, int rowIndex) throws Exception { + if (rowIndex == 0) { + return null; + } + Object o = this.clazz.newInstance(); + short lastCellNum = row.getLastCellNum(); + for (int cellIndex = 0; cellIndex < lastCellNum; cellIndex++) { + Cell cell = row.getCell(cellIndex); + ExcelEntityFieldDescription fieldDescription = indexColumnMap.get(cellIndex); + if (fieldDescription != null) { + fieldDescription.getReader().read(o, fieldDescription, row, rowIndex, cell, cellIndex); + } + } + return (T) o; + } + + public void writeHead(XSSFSheet sheet) { + XSSFRow row = sheet.createRow(0); + for (Map.Entry entry : indexColumnMap.entrySet()) { + XSSFCell cell = row.createCell(entry.getKey()); + cell.setCellValue(entry.getValue().getExcelColumn().title()); + } + } + + public void writeEntity(XSSFSheet sheet, T o, int dataIndex) throws Exception { + XSSFRow row = sheet.createRow(dataIndex + 1); + for (Map.Entry entry : indexColumnMap.entrySet()) { + XSSFCell cell = row.createCell(entry.getKey()); + ExcelEntityFieldDescription value = entry.getValue(); + value.getWriter().write(o, value, row, dataIndex + 1, cell, entry.getKey(), sheet); + } + } + + public void writeFoot(XSSFSheet sheet) { + for (Map.Entry entry : indexColumnMap.entrySet()) { + sheet.autoSizeColumn(entry.getKey()); + } + } + + /** + * + */ + private void analysis() { + // 解析类型 + ExcelRow annotation = (ExcelRow) this.clazz.getAnnotation(ExcelRow.class); + if (annotation != null) { + this.excelRow = annotation; + } + + // 解析字段 + ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() { + @Override + public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { + ExcelColumn annotation = field.getAnnotation(ExcelColumn.class); + if (annotation != null) { + try { + field.setAccessible(true); + ExcelEntityFieldDescription fieldDescription = ExcelEntityFieldDescription + .builder() + .excelColumn(annotation) + .field(field) + .reader(annotation.reader().newInstance()) + .writer(annotation.writer().newInstance()) + .build(); + indexColumnMap.put(annotation.order(), fieldDescription); + } catch (InstantiationException e) { + e.printStackTrace(); + } + } + } + }); + } + + +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/ExcelEntityFieldDescription.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/ExcelEntityFieldDescription.java new file mode 100644 index 0000000..7e49024 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/ExcelEntityFieldDescription.java @@ -0,0 +1,30 @@ +package com.chilunyc.fumao.common.util.excel; + +import com.chilunyc.fumao.common.util.excel.column.ExcelColumn; +import com.chilunyc.fumao.common.util.excel.column.ExcelColumnReader; +import com.chilunyc.fumao.common.util.excel.column.ExcelColumnWriter; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.lang.reflect.Field; + +/** + * 80347471@qq.com + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ExcelEntityFieldDescription { + + private ExcelColumn excelColumn; + + private Field field; + + private ExcelColumnReader reader; + + private ExcelColumnWriter writer; + +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/ExcelHelper.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/ExcelHelper.java new file mode 100644 index 0000000..7a92971 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/ExcelHelper.java @@ -0,0 +1,78 @@ +package com.chilunyc.fumao.common.util.excel; + +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.WorkbookFactory; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +import java.io.InputStream; +import java.io.OutputStream; +import java.util.*; + +/** + * 80347471@qq.com + */ +public class ExcelHelper { + + + public List read(InputStream inputStream, Class tClass) throws Exception { + return read(inputStream, tClass, 0); + } + + public List read(InputStream inputStream, Class tClass, int sheetIndex) throws Exception { + Workbook workbook = null; + List result = new ArrayList<>(); + try { + workbook = WorkbookFactory.create(inputStream); + Sheet sheet = workbook.getSheetAt(sheetIndex); + ExcelEntityDescription entityDescription = new ExcelEntityDescription(tClass); + int lastRowNum = sheet.getLastRowNum(); + for (int rowIndex = 0; rowIndex <= lastRowNum; rowIndex++) { + T entity = (T) entityDescription.read(sheet.getRow(rowIndex), rowIndex); + if (entity != null) { + result.add(entity); + } + } + } finally { + if (workbook != null) { + workbook.close(); + } + } + return result; + } + + public void write(List dataList, Class dataClass, OutputStream stream) throws Exception { + write( + Collections.singletonMap("sheet0", dataList), + Collections.singletonList(dataClass), + stream + ); + } + + public void write(Map sheetDataListMap, List dataClassList, OutputStream stream) throws Exception { + XSSFWorkbook workbook = new XSSFWorkbook(); + Set sheetNameSet = sheetDataListMap.keySet(); + int sheetIndex = 0; + for (String sheetName : sheetNameSet) { + List sheetDataList = sheetDataListMap.get(sheetName); + Class sheetDataClass = dataClassList.get(sheetIndex); + + // + ExcelEntityDescription entityDescription = new ExcelEntityDescription(sheetDataClass); + XSSFSheet sheet = workbook.createSheet(sheetName); + + // + entityDescription.writeHead(sheet); + for (int i = 0; i < sheetDataList.size(); i++) { + entityDescription.writeEntity(sheet, sheetDataList.get(i), i); + } + entityDescription.writeFoot(sheet); + + // + sheetIndex++; + } + workbook.write(stream); + } + +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/column/ExcelColumn.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/column/ExcelColumn.java new file mode 100644 index 0000000..ae21ced --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/column/ExcelColumn.java @@ -0,0 +1,26 @@ +package com.chilunyc.fumao.common.util.excel.column; + +import com.chilunyc.fumao.common.util.excel.column.impl.DefaultExcelColumnReaderWriter; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 80347471@qq.com + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ExcelColumn { + + String title() default ""; + + int order(); + + int width() default 0; + + Class reader() default DefaultExcelColumnReaderWriter.class; + + Class writer() default DefaultExcelColumnReaderWriter.class; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/column/ExcelColumnReader.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/column/ExcelColumnReader.java new file mode 100644 index 0000000..b1b64bb --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/column/ExcelColumnReader.java @@ -0,0 +1,21 @@ +package com.chilunyc.fumao.common.util.excel.column; + +import com.chilunyc.fumao.common.util.excel.ExcelEntityFieldDescription; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; + +/** + * 80347471@qq.com + */ +public interface ExcelColumnReader { + + /** + * @param o + * @param fieldDescription + * @param row + * @param rowIndex + * @param cell + * @param cellIndex + */ + void read(Object o, ExcelEntityFieldDescription fieldDescription, Row row, int rowIndex, Cell cell, int cellIndex) throws Exception; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/column/ExcelColumnWriter.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/column/ExcelColumnWriter.java new file mode 100644 index 0000000..e170eb8 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/column/ExcelColumnWriter.java @@ -0,0 +1,14 @@ +package com.chilunyc.fumao.common.util.excel.column; + +import com.chilunyc.fumao.common.util.excel.ExcelEntityFieldDescription; +import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFSheet; + +/** + * 80347471@qq.com + */ +public interface ExcelColumnWriter { + + void write(T o, ExcelEntityFieldDescription value, XSSFRow row, int rowIndex, XSSFCell cell, int cellIndex, XSSFSheet sheet) throws Exception; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/column/impl/DefaultExcelColumnReaderWriter.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/column/impl/DefaultExcelColumnReaderWriter.java new file mode 100644 index 0000000..9f4d015 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/column/impl/DefaultExcelColumnReaderWriter.java @@ -0,0 +1,105 @@ +package com.chilunyc.fumao.common.util.excel.column.impl; + +import com.chilunyc.fumao.common.util.CovertHelper; +import com.chilunyc.fumao.common.util.excel.ExcelEntityFieldDescription; +import com.chilunyc.fumao.common.util.excel.column.ExcelColumnReader; +import com.chilunyc.fumao.common.util.excel.column.ExcelColumnWriter; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.poi.hssf.usermodel.HSSFDateUtil; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFSheet; + +import java.lang.reflect.Field; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 80347471@qq.com + */ +public class DefaultExcelColumnReaderWriter implements ExcelColumnReader, ExcelColumnWriter { + + /** + * @param o + * @param fieldDescription + * @param row + * @param rowIndex + * @param cell + * @param cellIndex + */ + @Override + public void read(Object o, ExcelEntityFieldDescription fieldDescription, Row row, int rowIndex, Cell cell, int cellIndex) throws Exception { + String cellValue = null; + Field field = fieldDescription.getField(); + Class type = field.getType(); + switch (cell.getCellTypeEnum()) { + case NUMERIC: + // 是时间类型 + if (HSSFDateUtil.isCellDateFormatted(cell)) { + if (type.isAssignableFrom(Date.class)) { + field.set(o, cell.getDateCellValue()); + } else { + throw new UnsupportedOperationException(String.format("cell[%s] 是时间类型, class[%s] field[%s] 不是时间类型", cell.getCellTypeEnum(), o.getClass(), field.getName())); + } + } + // 不是时间类型 + else { + cellValue = cell.getNumericCellValue() + ""; + field.set(o, CovertHelper.stringTo(cellValue, type)); + } + break; + case STRING: + cellValue = cell.getStringCellValue(); + field.set(o, CovertHelper.stringTo(cellValue, type)); + break; + default: + throw new UnsupportedOperationException(String.format("cell[%s] class[%s] field[%s]", cell.getCellTypeEnum(), o.getClass(), field.getName())); + } + } + + /** + * @param o + * @param value + * @param row + * @param i + * @param cell + * @param key + * @param sheet + * @throws Exception + */ + @Override + public void write(Object o, ExcelEntityFieldDescription value, XSSFRow row, int rowIndex, XSSFCell cell, int cellIndex, XSSFSheet sheet) throws Exception { + Field field = value.getField(); + Object fieldValue = field.get(o); + Class type = field.getType(); + if (type.isAssignableFrom(String.class)) { + cell.setCellValue((String) fieldValue); + } + // + else if (type.isAssignableFrom(Integer.class) || type.isAssignableFrom(int.class)) { + cell.setCellValue((int) fieldValue); + } + // + else if (type.isAssignableFrom(Float.class) || type.isAssignableFrom(float.class)) { + cell.setCellValue((float) fieldValue); + } + // + else if (type.isAssignableFrom(Double.class) || type.isAssignableFrom(double.class)) { + cell.setCellValue((Double) fieldValue); + } + // + else if (type.isAssignableFrom(BigDecimal.class)) { + cell.setCellValue(((BigDecimal) fieldValue).toString()); + } + // + else if (type.isAssignableFrom(Date.class)) { + cell.setCellValue(DateFormatUtils.format(((Date) fieldValue), "yyyy-MM-dd HH:mm:ss")); + } + // + else { + throw new UnsupportedOperationException(String.format("src[%s] => class[%s]", fieldValue, type)); + } + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/row/ExcelRow.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/row/ExcelRow.java new file mode 100644 index 0000000..140f7b6 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/row/ExcelRow.java @@ -0,0 +1,18 @@ +package com.chilunyc.fumao.common.util.excel.row; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 80347471@qq.com + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface ExcelRow { + + Class reader(); + + Class writer(); +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/row/ExcelRowReader.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/row/ExcelRowReader.java new file mode 100644 index 0000000..cd4183d --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/row/ExcelRowReader.java @@ -0,0 +1,7 @@ +package com.chilunyc.fumao.common.util.excel.row; + +/** + * 80347471@qq.com + */ +public interface ExcelRowReader { +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/row/ExcelRowWriter.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/row/ExcelRowWriter.java new file mode 100644 index 0000000..baf94e5 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/excel/row/ExcelRowWriter.java @@ -0,0 +1,7 @@ +package com.chilunyc.fumao.common.util.excel.row; + +/** + * 80347471@qq.com + */ +public interface ExcelRowWriter { +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/config/HttpConfig.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/config/HttpConfig.java new file mode 100644 index 0000000..beb2d0c --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/config/HttpConfig.java @@ -0,0 +1,34 @@ +package com.chilunyc.fumao.common.util.http.config; + +import okhttp3.ConnectionPool; +import okhttp3.OkHttpClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.concurrent.TimeUnit; + +/** + * + */ +@Configuration +@EnableConfigurationProperties(HttpProperty.class) +public class HttpConfig { + + @Autowired + private HttpProperty sdkProperty; + + @Bean + OkHttpClient okHttpClient() { + return new OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.SECONDS) // + .followRedirects(false) // + .readTimeout(1, TimeUnit.MINUTES) // + .retryOnConnectionFailure(false) // + .writeTimeout(1, TimeUnit.MINUTES) + .connectionPool(new ConnectionPool(sdkProperty.getHttpMaxConnect(), sdkProperty.getHttpKeepAlice(), TimeUnit.MINUTES)) // + .build(); + } + +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/config/HttpProperty.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/config/HttpProperty.java new file mode 100644 index 0000000..b2f20ba --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/config/HttpProperty.java @@ -0,0 +1,18 @@ +package com.chilunyc.fumao.common.util.http.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * + */ +@Data +@ConfigurationProperties(prefix = "api") +public class HttpProperty { + + /** + * http 配置 + */ + private int httpMaxConnect = 10; + private long httpKeepAlice = 1; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/HttpClient.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/HttpClient.java new file mode 100644 index 0000000..c88fe4e --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/HttpClient.java @@ -0,0 +1,36 @@ +package com.chilunyc.fumao.common.util.http.service; + +import com.chilunyc.fumao.common.util.http.service.result.ResultExecute; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StopWatch; + +/** + * 80347471@qq.com + */ +@Component +public class HttpClient { + + @Autowired + private OkHttpClient client; + + public T execute(HttpParams params, ResultExecute resultExecute) { + Request request = params.toRequest(); + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + double consumeTime = 0; + try { + Response response = client.newCall(request).execute(); + stopWatch.stop(); + consumeTime = stopWatch.getTotalTimeSeconds(); + return (T) resultExecute.toBody(response, request, stopWatch); + } catch (HttpException e) { + throw e; + } catch (Exception e) { + throw HttpException.make(e, request, stopWatch); + } + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/HttpException.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/HttpException.java new file mode 100644 index 0000000..ddc2a52 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/HttpException.java @@ -0,0 +1,51 @@ +package com.chilunyc.fumao.common.util.http.service; + +import lombok.AllArgsConstructor; +import lombok.Data; +import okhttp3.Request; +import org.springframework.util.StopWatch; + +/** + * 80347471@qq.com + */ +@Data +@AllArgsConstructor +public class HttpException extends RuntimeException { + + private Request request; + + private StopWatch stopWatch; + + public HttpException() { + } + + public HttpException(String message) { + super(message); + } + + public HttpException(String message, Throwable cause) { + super(message, cause); + } + + public HttpException(Throwable cause) { + super(cause); + } + + public HttpException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public static HttpException make(String msg, Request req, StopWatch s){ + HttpException exception = new HttpException(msg); + exception.setRequest(req); + exception.setStopWatch(s); + return exception; + } + + public static HttpException make(Exception e, Request req, StopWatch s){ + HttpException exception = new HttpException(e); + exception.setRequest(req); + exception.setStopWatch(s); + return exception; + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/HttpMulitiParam.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/HttpMulitiParam.java new file mode 100644 index 0000000..167b304 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/HttpMulitiParam.java @@ -0,0 +1,25 @@ +package com.chilunyc.fumao.common.util.http.service; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import okhttp3.MediaType; + +import java.io.InputStream; + +/** + * 80347471@qq.com + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HttpMulitiParam { + + private String fileName; + + private InputStream inputStream; + + private MediaType mediaType; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/HttpParams.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/HttpParams.java new file mode 100644 index 0000000..55d8d18 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/HttpParams.java @@ -0,0 +1,255 @@ +package com.chilunyc.fumao.common.util.http.service; + + +import com.alibaba.fastjson.JSON; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import okhttp3.*; +import okio.BufferedSink; +import okio.Okio; +import okio.Source; +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.TreeMap; + +/** + * 80347471@qq.com + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HttpParams { + + public static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8"); + public static final MediaType MEDIA_TYPE_FILE = MediaType.parse("application/oct-stream"); + + private String method; + + private String url; + + private Map params; + + private boolean json; + + private boolean file; + + private String userAgent; + + private Map heads; + + public HttpParams put(String name, Object value) { + if (params == null) { + params = new TreeMap<>(); + } + params.put(name, value); + return this; + } + + public Request toRequest() { + Request.Builder request; + switch (method.toUpperCase()) { + case "GET": + request = this.toGet(); + break; + case "POST": + request = this.toPost(); + break; + default: + throw new RuntimeException("not support => " + method); + } + if (StringUtils.isNotBlank(userAgent)) { + request.addHeader("User-Agent", userAgent); + } + if (heads != null) { + heads.forEach((k, v) -> { + request.addHeader(k, v); + }); + } + return request.build(); + } + + + private Request.Builder toGet() { + HttpUrl.Builder builder = HttpUrl.parse(url).newBuilder(); + if (params != null) { + params.forEach((k, v) -> { + if (v == null) { + return; + } + builder.addEncodedQueryParameter(k, v.toString()); + }); + } + return new Request.Builder().url(builder.build()); + } + + private Request.Builder toPost() { + // json提交 + if (json) { + String jsonString = JSON.toJSONString(params); + RequestBody body = RequestBody.create(MEDIA_TYPE_JSON, jsonString); + return new Request.Builder().url(url).post(body); + } + // 上传文件 + else if (file) { + MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM); + params.forEach((k, v) -> { + if (v == null) { + return; + } + if (v instanceof File) { + File f = (File) v; + builder.addFormDataPart( + k, f.getName(), RequestBody.create(MEDIA_TYPE_FILE, f) + ); + } else if (v instanceof InputStream) { + builder.addFormDataPart( + k, k, create(MEDIA_TYPE_FILE, (InputStream) v) + ); + } else if (v instanceof HttpMulitiParam) { + HttpMulitiParam p = (HttpMulitiParam) v; + builder.addFormDataPart( + k, p.getFileName(), create(p.getMediaType(), p.getInputStream()) + ); + } + // + else { + builder.addFormDataPart(k, v.toString()); + } + }); + return new Request.Builder().url(url).post(builder.build()); + } + // 上传 + else { + FormBody.Builder builder = new FormBody.Builder(); + if (params != null) { + params.forEach((k, v) -> { + if (v == null) { + return; + } + builder.addEncoded(k, v.toString()); + }); + } + return new Request.Builder().url(url).post(builder.build()); + } + } + + /** + * @param mediaType + * @param inputStream + * @return + */ + public static RequestBody create(final MediaType mediaType, final InputStream inputStream) { + return new RequestBody() { + @Override + public MediaType contentType() { + return mediaType; + } + + @Override + public long contentLength() { + try { + return inputStream.available(); + } catch (IOException e) { + return 0; + } + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + Source source = null; + try { + source = Okio.source(inputStream); + sink.writeAll(source); + } finally { + } + } + }; + } + + /** + * @param url + * @return + */ + public static HttpParams get(String url) { + return HttpParams + .builder() + .url(url) + .method("GET") + .params(new TreeMap<>()) + .build(); + } + + /** + * @param url + * @return + */ + public static HttpParams get(String url, Map params) { + return HttpParams + .builder() + .url(url) + .params(params) + .method("GET") + .build(); + } + + /** + * @param url + * @return + */ + public static HttpParams post(String url, Map params) { + return HttpParams + .builder() + .url(url) + .params(params) + .method("POST") + .build(); + } + + /** + * @param url + * @return + */ + public static HttpParams postFile(String url, Map params) { + return HttpParams + .builder() + .url(url) + .params(params) + .method("POST") + .file(true) + .build(); + } + + /** + * @param url + * @return + */ + public static HttpParams postJson(String url, Map params) { + return HttpParams + .builder() + .url(url) + .params(params) + .method("POST") + .json(true) + .build(); + } + + + public HttpParams putHead(String k, String v) { + if (heads == null){ + heads = new TreeMap<>(); + } + heads.put(k, v); + return this; + } + + +} + + diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/UrlBuilder.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/UrlBuilder.java new file mode 100644 index 0000000..5188d6c --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/UrlBuilder.java @@ -0,0 +1,40 @@ +package com.chilunyc.fumao.common.util.http.service; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Map; + +/** + * 80347471@qq.com + */ +@Data +@AllArgsConstructor +public class UrlBuilder { + + private String url; + + private Map map; + + public String toString() { + StringBuilder sb = new StringBuilder(200); + sb.append(url); + if (!url.contains("?")) { + sb.append("?"); + } + map.forEach((k, v) -> { + try { + sb + .append(k) + .append("=") + .append(URLEncoder.encode(v.toString(), "utf-8")) + .append("&"); + } catch (UnsupportedEncodingException e) { + } + }); + sb.trimToSize(); + return sb.subSequence(0, sb.length() - 1).toString(); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/ByteResultExecute.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/ByteResultExecute.java new file mode 100644 index 0000000..6570a9e --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/ByteResultExecute.java @@ -0,0 +1,25 @@ +package com.chilunyc.fumao.common.util.http.service.result; + +import com.chilunyc.fumao.common.util.http.service.HttpException; +import okhttp3.Request; +import okhttp3.Response; +import org.springframework.util.StopWatch; + +import java.io.IOException; + +/** + * 80347471@qq.com + */ +public class ByteResultExecute implements ResultExecute { + + + @Override + public byte[] toBody(Response response, Request request, StopWatch stopWatch) throws IOException { + switch (response.code()) { + case 200: + return response.body().bytes(); + default: + throw HttpException.make(response.code() + " ==> " + response.body().string(), request, stopWatch); + } + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/JsonArrayResultExecute.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/JsonArrayResultExecute.java new file mode 100644 index 0000000..5bb0727 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/JsonArrayResultExecute.java @@ -0,0 +1,28 @@ +package com.chilunyc.fumao.common.util.http.service.result; + +import com.alibaba.fastjson.JSON; +import lombok.Builder; +import lombok.Data; +import okhttp3.Request; +import okhttp3.Response; +import org.springframework.util.StopWatch; + +import java.io.IOException; +import java.util.List; + +/** + * 80347471@qq.com + */ +@Data +@Builder +public class JsonArrayResultExecute { + + private final StringResultExecute stringResultExecute = new StringResultExecute(); + + private Class clazz; + + public List toBody(Response response, Request request, StopWatch stopWatch) throws IOException { + String body = stringResultExecute.toBody(response, request, stopWatch); + return JSON.parseArray(body, (Class) clazz); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/JsonObjectResultExecute.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/JsonObjectResultExecute.java new file mode 100644 index 0000000..331f4d8 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/JsonObjectResultExecute.java @@ -0,0 +1,27 @@ +package com.chilunyc.fumao.common.util.http.service.result; + +import com.alibaba.fastjson.JSON; +import lombok.Builder; +import lombok.Data; +import okhttp3.Request; +import okhttp3.Response; +import org.springframework.util.StopWatch; + +import java.io.IOException; + +/** + * 80347471@qq.com + */ +@Data +@Builder +public class JsonObjectResultExecute { + + private final StringResultExecute stringResultExecute = new StringResultExecute(); + + private Class clazz; + + public T toBody(Response response, Request request, StopWatch stopWatch) throws IOException { + String body = stringResultExecute.toBody(response, request, stopWatch); + return JSON.parseObject(body, (Class) clazz); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/ResultExecute.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/ResultExecute.java new file mode 100644 index 0000000..b33ecdc --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/ResultExecute.java @@ -0,0 +1,16 @@ +package com.chilunyc.fumao.common.util.http.service.result; + + +import okhttp3.Request; +import okhttp3.Response; +import org.springframework.util.StopWatch; + +import java.io.IOException; + +/** + * 80347471@qq.com + */ +public interface ResultExecute { + + T toBody(Response response, Request request, StopWatch stopWatch) throws Exception; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/StringResultExecute.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/StringResultExecute.java new file mode 100644 index 0000000..cfad8f9 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/http/service/result/StringResultExecute.java @@ -0,0 +1,25 @@ +package com.chilunyc.fumao.common.util.http.service.result; + +import com.chilunyc.fumao.common.util.http.service.HttpException; +import okhttp3.Request; +import okhttp3.Response; +import org.springframework.util.StopWatch; + +import java.io.IOException; + +/** + * 80347471@qq.com + */ +public class StringResultExecute implements ResultExecute { + + + @Override + public String toBody(Response response, Request request, StopWatch stopWatch) throws IOException { + switch (response.code()){ + case 200: + return response.body().string(); + default: + throw HttpException.make(response.code() + " ==> " + response.body().string(), request, stopWatch); + } + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/CustomIdentifierGenerator.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/CustomIdentifierGenerator.java new file mode 100644 index 0000000..92c0f72 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/CustomIdentifierGenerator.java @@ -0,0 +1,55 @@ +package com.chilunyc.fumao.common.util.jpa; + +import com.chilunyc.fumao.common.util.jpa.generator.SnowflaskGenerator; +import org.apache.commons.lang.time.DateFormatUtils; +import org.apache.commons.lang3.StringUtils; +import org.hibernate.HibernateException; +import org.hibernate.MappingException; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.id.Configurable; +import org.hibernate.id.IdentifierGenerator; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.type.Type; + +import java.io.Serializable; +import java.util.Date; +import java.util.Properties; +import java.util.UUID; + +/** + * + */ +public class CustomIdentifierGenerator implements IdentifierGenerator, Configurable { + + private String type; + private Properties props; + private String entityName; + + private SnowflaskGenerator snowflaskGenerator = new SnowflaskGenerator(1L); + + @Override + public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException { + this.type = params.get("type").toString().toLowerCase(); + this.props = params; + entityName = params.getProperty(ENTITY_NAME); + } + + @Override + public Serializable generate(SessionImplementor session, Object object) throws HibernateException { + Serializable id = session + .getEntityPersister(entityName, object) + .getIdentifier(object, session); + if (id != null && StringUtils.isNotBlank(id.toString())) { + return id; + } + switch (type) { + case "number": + return snowflaskGenerator.generate(); + case "datetime": + return DateFormatUtils.format(new Date(), "yyyyMMddHHmmss"); + default: + String uuid = UUID.randomUUID().toString().replaceAll("-", ""); + return uuid; + } + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/coverter/AesConverter.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/coverter/AesConverter.java new file mode 100644 index 0000000..6a8c36c --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/coverter/AesConverter.java @@ -0,0 +1,45 @@ +package com.chilunyc.fumao.common.util.jpa.coverter; + +import com.chilunyc.fumao.common.config.ApplicationProperty; +import com.chilunyc.fumao.common.util.CryptoHelper; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; + +/** + * 80347471@qq.com + */ +@Converter +public class AesConverter implements AttributeConverter, ApplicationContextAware { + + private static ApplicationProperty applicationProperty; + + public AesConverter() { + } + + @Override + public String convertToDatabaseColumn(String attribute) { + try { + return CryptoHelper.aesEncrypt(applicationProperty.getAesKey(), attribute); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public String convertToEntityAttribute(String dbData) { + try { + return CryptoHelper.aesDecrypt(applicationProperty.getAesKey(), dbData); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + applicationProperty = applicationContext.getBean(ApplicationProperty.class); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/coverter/JsonConverter.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/coverter/JsonConverter.java new file mode 100644 index 0000000..b52a508 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/coverter/JsonConverter.java @@ -0,0 +1,24 @@ +package com.chilunyc.fumao.common.util.jpa.coverter; + +import com.alibaba.fastjson.JSON; +import org.apache.commons.lang3.StringUtils; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; + +/** + * 80347471@qq.com + */ +@Converter +public class JsonConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(Object attribute) { + return JSON.toJSONString(attribute == null ? new Object() : attribute); + } + + @Override + public Object convertToEntityAttribute(String dbData) { + return StringUtils.isNotBlank(dbData) ? JSON.parse(dbData) : null; + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/generator/SnowflaskGenerator.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/generator/SnowflaskGenerator.java new file mode 100644 index 0000000..20f4b43 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/generator/SnowflaskGenerator.java @@ -0,0 +1,130 @@ +package com.chilunyc.fumao.common.util.jpa.generator; + +import lombok.extern.log4j.Log4j; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; +import java.util.stream.IntStream; + +/** + * Long类型ID生成器,固定为19位长度 + * 生成ID,采用snowflake算法,64bit整数,1秒可以生成800万个ID + * 0-41bit毫秒时间戳-10bit机器ID-12bit序列化 + * 42bit的毫秒时间戳,2000年算起可以支持该算法使用到2068年,10bit的工作机器id可以支持1024台机器,12序列号支持1毫秒产生4096个自增序列id + */ +@Log4j +public class SnowflaskGenerator { + + private String startTimeString = "2010-01-01 00:00:00"; + + + /** + * 起始的时间戳, 2016-01-01 00:00:00 + */ + private long startStamp = getTimeStamp(startTimeString); + + /** + * 每一部分占用的位数 + */ + private long sequenceBit = 12; //序列号占用的位数 + private long machineBit = 2; //机器标识占用的位数, 不会超过100台机器 + + /** + * 每一部分的最大值 + */ + private long maxSequence = ~(-1L << sequenceBit); + + /** + * 每一部分向左的位移 + */ + private long machineLeft = sequenceBit; + private long timestampLeft = sequenceBit + machineBit; + + private long machineId; //机器标识,采用IP地址的后两段,16bit的工作机器id可以支持65536台机器 + private long sequence = 0L; //序列号,13序列号支持1毫秒产生8192个自增序列id + private long lastStamp = -1L;//上一次时间戳 + + public SnowflaskGenerator(Long machineId) { + this.machineId = machineId; + } + + + /** + * 生成ID,采用snowflake算法,64bit整数,1秒可以生成800万个ID + * 0-41bit毫秒时间戳-10bit机器ID-12bit序列化 + * 42bit的毫秒时间戳,2000年算起可以支持该算法使用到2068年,10bit的工作机器id可以支持1024台机器,12序列号支持1毫秒产生4096个自增序列id + * + * @return 返回Long ID + */ + public synchronized Long generate() { + long curStamp = getCurrentStamp(); + if (curStamp < lastStamp) { + throw new IllegalArgumentException("Clock moved backwards. Refusing to generate id"); + } + + if (curStamp == lastStamp) { + //相同毫秒内,序列号自增 + sequence = (sequence + 1) & maxSequence; + //同一毫秒的序列数已经达到最大 + if (sequence == 0L) { + curStamp = getNextMill(); + } + } else { + //不同毫秒内,序列号置为0 + sequence = 0L; + } + + lastStamp = curStamp; + return (curStamp - startStamp) << timestampLeft //时间戳部分 + | machineId << machineLeft //机器标识部分 + | sequence; //序列号部分 + } + + /** + * 获取下一毫秒 + * + * @return 下一毫秒 + */ + private long getNextMill() { + long mill = getCurrentStamp(); + while (mill <= lastStamp) { + mill = getCurrentStamp(); + } + return mill; + } + + /** + * 获取当前时间戳, 改为秒 + * + * @return 时间戳 + */ + private long getCurrentStamp() { + return System.currentTimeMillis(); + } + + /** + * 获取起始时间戳,因为要兼容java7,使用Date对象 + * + * @param dateStr 时间字符串,格式由startTimeFormatter指定 + * @return 时间戳 + */ + private long getTimeStamp(String dateStr) { + try { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + formatter.setTimeZone(TimeZone.getTimeZone("GMT+0800")); + Date startDate = formatter.parse(dateStr); + return startDate.getTime(); + } catch (Exception e) { + log.error(e.getMessage(), e); + return 1262275200000L; + } + } + + public static void main(String[] args) { + SnowflaskGenerator snowflaskGenerator = new SnowflaskGenerator(1l); + IntStream.range(0, 100).forEach(i -> { + System.out.println(snowflaskGenerator.generate()); + }); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/QueryBuilder.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/QueryBuilder.java new file mode 100644 index 0000000..63e1bb2 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/QueryBuilder.java @@ -0,0 +1,157 @@ +package com.chilunyc.fumao.common.util.jpa.query; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.apache.commons.lang.StringUtils; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.util.ReflectionUtils; + +import javax.persistence.criteria.Predicate; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Created by Tkk on 2018/7/21. + */ +public class QueryBuilder { + + @Data + @AllArgsConstructor + private static class QueryDesc { + Field field; + QueryItem queryItem; + } + + /** + * 查询缓存 + */ + private static Map> classQueryDescMap = new ConcurrentHashMap<>(); + + + /** + * @param object + * @param + * @return + */ + public static Specification build(Object object) { + + + /** + * + */ + return (root, criteriaQuery, cb) -> { + Class clazz = object.getClass(); + List descMap = getQueryDescMap(clazz); + List predicates = new ArrayList<>(descMap.size()); + descMap.forEach(desc -> { + Object value = getValue(desc.field, object); + + // 为null不加入查询 + if (value == null && !desc.queryItem.nullable()) { + return; + } + + // 字符串为""不加入查询 + if (value != null && value instanceof String && !desc.queryItem.blankable() && StringUtils.isBlank(value.toString())) { + return; + } + + // + String path = desc.queryItem.column(); + if (StringUtils.isBlank(path)) { + path = desc.field.getName(); + } + + // + switch (desc.queryItem.type()) { + case equal: + predicates.add(cb.equal(root.get(path), value)); + break; + case like: + predicates.add(cb.like(root.get(path), "%" + value + "%")); + break; + case gt: + predicates.add(cb.gt(root.get(path), (Number) value)); + break; + case lt: + predicates.add(cb.lt(root.get(path), (Number) value)); + break; + case ge: + predicates.add(cb.ge(root.get(path), (Number) value)); + break; + case le: + predicates.add(cb.le(root.get(path), (Number) value)); + break; + case notEqual: + predicates.add(cb.notEqual(root.get(path), value)); + break; + case notLike: + predicates.add(cb.notLike(root.get(path), "%" + value + "%")); + break; + case rightLike: + predicates.add(cb.like(root.get(path), value + "%")); + break; + } + }); + + SortItems sortItems = (SortItems) clazz.getAnnotation(SortItems.class); + if (sortItems != null && sortItems.value() != null) { + for (SortItem sortItem : sortItems.value()) { + if (sortItem.desc()) { + criteriaQuery.orderBy(cb.desc(root.get(sortItem.column()))); + } else { + criteriaQuery.orderBy(cb.asc(root.get(sortItem.column()))); + } + } + } + return cb.and(predicates.toArray(new Predicate[predicates.size()])); + }; + } + + private static Object getValue(Field field, Object src) { + try { + return field.get(src); + } catch (IllegalAccessException e) { + return null; + } + } + + private static List getQueryDescMap(Class clazz) { + List queryDescs = classQueryDescMap.get(clazz); + if (queryDescs != null) { + return queryDescs; + } + synchronized (clazz.getName()) { + queryDescs = classQueryDescMap.get(clazz); + if (queryDescs != null) { + return queryDescs; + } + + // 组装 + List real = new ArrayList<>(); + ReflectionUtils.doWithFields(clazz, (field) -> { + QueryDesc queryDec = getQueryDec(field); + if (queryDec == null) { + return; + } + field.setAccessible(true); + real.add(queryDec); + }); + + // + return real; + } + } + + private static QueryDesc getQueryDec(Field field) { + QueryItem annotation = field.getAnnotation(QueryItem.class); + if (annotation == null) { + return null; + } + return new QueryDesc(field, annotation); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/QueryItem.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/QueryItem.java new file mode 100644 index 0000000..51f9276 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/QueryItem.java @@ -0,0 +1,42 @@ +package com.chilunyc.fumao.common.util.jpa.query; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created by Tkk on 2018/7/21. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface QueryItem { + + /** + * 数据库字段 + * + * @return + */ + String column() default ""; + + + /** + * @return + */ + QueryType type() default QueryType.equal; + + + /** + * object是否可以为null + * + * @return + */ + boolean nullable() default false; + + /** + * 字符串是否可为空 + * + * @return + */ + boolean blankable() default false; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/QueryType.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/QueryType.java new file mode 100644 index 0000000..4aa979a --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/QueryType.java @@ -0,0 +1,40 @@ +package com.chilunyc.fumao.common.util.jpa.query; + +/** + * Created by Tkk on 2018/7/21. + */ +public enum QueryType { + + // 等于 + equal, + + // 大于 + gt, + + // 大于等于 + ge, + + // 小于 + lt, + + // 小于等于 + le, + + // 不等于, 少用。。负向查询性能底下 + notEqual, + + // + like, + + // 右% + rightLike, + + // + notLike, + + // + bwtween, + + + ; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/SortItem.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/SortItem.java new file mode 100644 index 0000000..2436303 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/SortItem.java @@ -0,0 +1,27 @@ +package com.chilunyc.fumao.common.util.jpa.query; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created by Tkk on 2018/7/21. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface SortItem { + + /** + * 数据库字段 + * + * @return + */ + String column() default ""; + + + /** + * @return + */ + boolean desc() default true; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/SortItems.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/SortItems.java new file mode 100644 index 0000000..7ca9e2b --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jpa/query/SortItems.java @@ -0,0 +1,16 @@ +package com.chilunyc.fumao.common.util.jpa.query; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created by Tkk on 2018/7/21. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface SortItems { + + SortItem[] value(); +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jwt/JwtUtils.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jwt/JwtUtils.java new file mode 100644 index 0000000..d40c968 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jwt/JwtUtils.java @@ -0,0 +1,85 @@ +package com.chilunyc.fumao.common.util.jwt; + +import com.chilunyc.fumao.common.context.LoginUser; +import com.chilunyc.fumao.common.exception.SystemException; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtBuilder; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +/** + * + */ +@Component +public class JwtUtils implements ApplicationContextAware { + + private static SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS512; + + private static StringRedisTemplate redisTemplate; + + public enum T { + System(DigestUtils.md5Hex("System")), + Company(DigestUtils.md5Hex("Company")), + Market(DigestUtils.md5Hex("Market")), + APP_C(DigestUtils.md5Hex("APP_C")), + APP_B(DigestUtils.md5Hex("APP_B")),; + private String key; + + T(String key) { + this.key = key; + } + } + + /** + * @param jwtToken + * @return + */ + public static Claims decode(JwtUtils.T t, String jwtToken) { + try { + if (StringUtils.isBlank(jwtToken)) { + throw new RuntimeException(); + } +// String body = jwtToken.split("\\.")[1]; +// String s = jodd.util.Base64.decodeToString(body); +// Map m = JSON.parseObject(s); +// String key = redisTemplate.boundValueOps(t.name() + m.get("sub")).get(); + Claims claims = Jwts.parser().setSigningKey(t.key).parseClaimsJws(jwtToken).getBody(); + return claims; + } catch (Exception e) { + throw new SystemException("000002"); + } + } + + /** + * @param user + * @return + */ + public static String encode(JwtUtils.T t, LoginUser user) { +// String id = user.getId().toString(); +// String key = RandomStringUtils.randomAlphabetic(16); +// redisTemplate.boundValueOps(t.name() + id).set(key, 24, TimeUnit.HOURS); + JwtBuilder builder = Jwts.builder(); + user.toJwt(builder); + String jwtBuilder = builder.signWith(signatureAlgorithm, t.key) + .claim("role", user.toRoles()) + .compact(); + return jwtBuilder; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + redisTemplate = applicationContext.getBean(StringRedisTemplate.class); + } + + public static void remove(LoginUser manager) { + String id = manager.getId().toString(); + redisTemplate.delete(id); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jwt/JwtValue.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jwt/JwtValue.java new file mode 100644 index 0000000..330f8f8 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/jwt/JwtValue.java @@ -0,0 +1,24 @@ +package com.chilunyc.fumao.common.util.jwt; + +import io.jsonwebtoken.Claims; + +/** + * + */ +public interface JwtValue { + + /** + * 从JWT内容转换 + * + * @param claims + * @return + */ + T fromJwt(Claims claims); + + /** + * 转换JWT的内容 + * + * @return + */ + String toJwt(); +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/security/SaltHelper.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/security/SaltHelper.java new file mode 100644 index 0000000..9b04daa --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/security/SaltHelper.java @@ -0,0 +1,40 @@ +package com.chilunyc.fumao.common.util.security; + + +import org.apache.commons.codec.digest.DigestUtils; + +import java.util.UUID; + +/** + * + */ +public class SaltHelper { + + /** + * 比较相等 + * + * @param src + * @param give + * @param salt + * @return + */ + public static boolean isEquals(String src, String give, String salt) { + return src.equals(exec(give, salt)); + } + + /** + * @param give + * @param salt + * @return + */ + public static String exec(String give, String salt) { + return DigestUtils.md5Hex(give + DigestUtils.md5Hex(salt)); + } + + /** + * @return + */ + public static String salt() { + return DigestUtils.md5Hex(UUID.randomUUID().toString()); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/valid/Captcha.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/valid/Captcha.java new file mode 100644 index 0000000..d28af2c --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/valid/Captcha.java @@ -0,0 +1,22 @@ +package com.chilunyc.fumao.common.util.valid; + +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; + +/** + * + */ +@Target({ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = CaptchaValidator.class) +public @interface Captcha { + String message() default "图形验证码错误"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/valid/CaptchaValidator.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/valid/CaptchaValidator.java new file mode 100644 index 0000000..aaee4d4 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/valid/CaptchaValidator.java @@ -0,0 +1,27 @@ +package com.chilunyc.fumao.common.util.valid; + +import com.chilunyc.fumao.common.context.RequestHolder; +import com.google.code.kaptcha.Constants; +import org.apache.commons.lang.StringUtils; + +import javax.servlet.http.HttpSession; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +/** + * + */ +public class CaptchaValidator implements ConstraintValidator { + + @Override + public void initialize(Captcha captcha) { + } + + @Override + public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) { + HttpSession session = RequestHolder.get().getSession(); + String key = (String) session.getAttribute(Constants.KAPTCHA_SESSION_KEY); +// session.removeAttribute(Constants.KAPTCHA_SESSION_KEY); + return StringUtils.equalsIgnoreCase(key, s); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/valid/Geo.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/valid/Geo.java new file mode 100644 index 0000000..af4eec7 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/valid/Geo.java @@ -0,0 +1,22 @@ +package com.chilunyc.fumao.common.util.valid; + +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; + +/** + * + */ +@Target({ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = GeoValidator.class) +public @interface Geo { + String message() default "经度或者纬度错误"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/util/valid/GeoValidator.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/valid/GeoValidator.java new file mode 100644 index 0000000..d6748cb --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/util/valid/GeoValidator.java @@ -0,0 +1,25 @@ +package com.chilunyc.fumao.common.util.valid; + +import org.apache.commons.lang3.StringUtils; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +/** + * + */ +public class GeoValidator implements ConstraintValidator { + + + @Override + public void initialize(Geo geo) { + } + + @Override + public boolean isValid(Double aDouble, ConstraintValidatorContext constraintValidatorContext) { + if (aDouble == null) { + return false; + } + return StringUtils.contains(aDouble.toString(), "."); + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/config/WechatConfiguration.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/config/WechatConfiguration.java new file mode 100644 index 0000000..a513b5b --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/config/WechatConfiguration.java @@ -0,0 +1,47 @@ +package com.chilunyc.fumao.common.weixin.config; + +import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage; +import me.chanjar.weixin.mp.api.WxMpService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * + */ +@Configuration +@ConditionalOnProperty(name = "wechat.mp.app-id") +@EnableConfigurationProperties({ + WechatMpProperties.class, +}) +public class WechatConfiguration { + + @Autowired + private WechatMpProperties properties; + + /** + * 服务号 + * + * @return + */ + @Bean + public WxMpConfigStorage configStorage() { + WxMpInMemoryConfigStorage configStorage = new WxMpInMemoryConfigStorage(); + configStorage.setAppId(this.properties.getAppId()); + configStorage.setSecret(this.properties.getSecret()); + configStorage.setToken(this.properties.getToken()); + configStorage.setAesKey(this.properties.getAesKey()); + return configStorage; + } + + @Bean + public WxMpService wxMpService(WxMpConfigStorage configStorage) { + WxMpService wxMpService = new me.chanjar.weixin.mp.api.impl.WxMpServiceImpl(); + wxMpService.setWxMpConfigStorage(configStorage); + return wxMpService; + } + +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/config/WechatMaConfiguration.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/config/WechatMaConfiguration.java new file mode 100644 index 0000000..f3d59fb --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/config/WechatMaConfiguration.java @@ -0,0 +1,40 @@ +package com.chilunyc.fumao.common.weixin.config; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.config.WxMaInMemoryConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 80347471@qq.com + */ +@Configuration +@ConditionalOnProperty(name = "wechat.ma.app-id") +@EnableConfigurationProperties({ + WechatMaProperties.class, +}) +public class WechatMaConfiguration { + + @Autowired + private WechatMaProperties wechatMaProperties; + + @Bean + public WxMaConfig maConfig() { + WxMaInMemoryConfig config = new WxMaInMemoryConfig(); + config.setAppid(this.wechatMaProperties.getAppId()); + config.setSecret(this.wechatMaProperties.getSecret()); + return config; + } + + @Bean + public WxMaService wxMaService(WxMaConfig maConfig) { + WxMaService service = new WxMaServiceImpl(); + service.setWxMaConfig(maConfig); + return service; + } +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/config/WechatMaProperties.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/config/WechatMaProperties.java new file mode 100644 index 0000000..ddca25c --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/config/WechatMaProperties.java @@ -0,0 +1,23 @@ +package com.chilunyc.fumao.common.weixin.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * + */ +@Data +@ConfigurationProperties(prefix = "wechat.ma") +public class WechatMaProperties { + /** + * 设置微信公众号的appid + */ + private String appId; + + /** + * 设置微信公众号的app secret + */ + private String secret; + + +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/config/WechatMpProperties.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/config/WechatMpProperties.java new file mode 100644 index 0000000..5f48036 --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/config/WechatMpProperties.java @@ -0,0 +1,46 @@ +package com.chilunyc.fumao.common.weixin.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * + */ +@Data +@ConfigurationProperties(prefix = "wechat.mp") +public class WechatMpProperties { + /** + * 设置微信公众号的appid + */ + private String appId; + + /** + * 设置微信公众号的app secret + */ + private String secret; + + /** + * 设置微信公众号的token + */ + private String token; + + /** + * 设置微信公众号的EncodingAESKey + */ + private String aesKey; + + /** + * 微信支付商户号 + */ + private String mchId; + + /** + * 微信支付商户密钥 + */ + private String mchKey; + + /** + * apiclient_cert.p12的文件的绝对路径 + */ + private String keyPath; +} diff --git a/fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/request/WxMaUserInfoRequest.java b/fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/request/WxMaUserInfoRequest.java new file mode 100644 index 0000000..29f987c --- /dev/null +++ b/fumao-common/src/main/java/com/chilunyc/fumao/common/weixin/request/WxMaUserInfoRequest.java @@ -0,0 +1,20 @@ +package com.chilunyc.fumao.common.weixin.request; + +import lombok.Data; + +/** + * 80347471@qq.com + */ +@Data +public class WxMaUserInfoRequest { + + private String openId; + + private String signature; + + private String rawData; + + private String encryptedData; + + private String iv; +} diff --git a/fumao-common/src/main/lib/aliyun-java-sdk-core-3.2.2.jar b/fumao-common/src/main/lib/aliyun-java-sdk-core-3.2.2.jar new file mode 100644 index 0000000000000000000000000000000000000000..d0f2e8d00efddf4eab6316ec7c24edaac2de295e GIT binary patch literal 84648 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 Bf}Q{X literal 0 HcmV?d00001 diff --git a/fumao-common/src/main/lib/aliyun-java-sdk-dysmsapi-1.0.0-SANPSHOT.jar b/fumao-common/src/main/lib/aliyun-java-sdk-dysmsapi-1.0.0-SANPSHOT.jar new file mode 100644 index 0000000000000000000000000000000000000000..de67807096cb8526e74b155889e20c9e8773c588 GIT binary patch literal 17951 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 DHylw< literal 0 HcmV?d00001 diff --git a/fumao-common/src/main/resources/com/chilunyc/fumao/common/log/repository/LogMapper.xml b/fumao-common/src/main/resources/com/chilunyc/fumao/common/log/repository/LogMapper.xml new file mode 100644 index 0000000..8fa314b --- /dev/null +++ b/fumao-common/src/main/resources/com/chilunyc/fumao/common/log/repository/LogMapper.xml @@ -0,0 +1,36 @@ + + + + + + \ No newline at end of file diff --git a/fumao-company/pom.xml b/fumao-company/pom.xml new file mode 100644 index 0000000..515fa5d --- /dev/null +++ b/fumao-company/pom.xml @@ -0,0 +1,22 @@ + + + + fumao + com.aki + 0.0.1-SNAPSHOT + + 4.0.0 + + fumao-company + + + + + com.aki + fumao-common + 0.0.1-SNAPSHOT + + + \ No newline at end of file diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/model/Company.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/model/Company.java new file mode 100644 index 0000000..36e76b9 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/model/Company.java @@ -0,0 +1,105 @@ +package com.chilunyc.fumao.company.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.*; +import org.hibernate.annotations.Parameter; +import org.hibernate.validator.constraints.*; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.validation.constraints.*; + +import javax.persistence.*; +import javax.persistence.Entity; +import javax.persistence.Index; +import javax.persistence.Table; +import java.io.Serializable; +import java.lang.Long; +import java.lang.String; +import java.lang.String; +import java.lang.String; +import java.lang.String; +import java.lang.String; +import java.lang.String; +import java.lang.String; +import java.util.Date; + +/** +* +*/ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Entity +@Table(name = "fumao_company", indexes = { +}) +@EntityListeners(AuditingEntityListener.class) +public class Company implements Serializable { + + /** + * 编号 + */ + @Id + @Column(columnDefinition = "bigint(64)") + @GeneratedValue(generator = "custom") + @GenericGenerator(name = "custom", strategy = "com.chilunyc.fumao.common.util.jpa.CustomIdentifierGenerator", parameters = {@Parameter(name = "type", value = "Number")}) + private Long id; + + /** + * 名称 + */ + @Column(columnDefinition = "varchar(64) comment '名称'") + private String name; + + /** + * 省份 + */ + @Column(columnDefinition = "varchar(10) comment '省份'") + private String province; + + /** + * 城市 + */ + @Column(columnDefinition = "varchar(10) comment '城市'") + private String city; + + /** + * 区域 + */ + @Column(columnDefinition = "varchar(10) comment '区域'") + private String area; + + /** + * POI + */ + @Column(columnDefinition = "varchar(64) comment 'POI'") + private String poi; + + /** + * 经度 + */ + @Column(columnDefinition = "varchar(12) comment '经度'") + private String lat; + + /** + * 纬度 + */ + @Column(columnDefinition = "varchar(12) comment '纬度'") + private String lng; + + /** + * 地址 + */ + @Column(columnDefinition = "varchar(64) comment '地址'") + private String address; + + /** + * 创建时间 + */ + @CreatedDate + private Date createTime; +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/model/CompanyAdmin.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/model/CompanyAdmin.java new file mode 100644 index 0000000..b5a0c11 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/model/CompanyAdmin.java @@ -0,0 +1,119 @@ +package com.chilunyc.fumao.company.model; + +import com.chilunyc.fumao.common.context.LoginUser; +import com.chilunyc.fumao.common.shiro.AuthRoles; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtBuilder; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.*; +import org.hibernate.annotations.Parameter; + +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.*; +import javax.persistence.Entity; +import javax.persistence.ForeignKey; +import javax.persistence.Index; +import javax.persistence.Table; +import java.io.Serializable; +import java.util.Date; +import java.lang.Long; +import java.lang.String; + +/** + * + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Entity +@Table(name = "fumao_company_admin", indexes = { + @Index(name = "company_admin_mobile", columnList = "mobile"), +}) +@EntityListeners(AuditingEntityListener.class) +public class CompanyAdmin implements Serializable, LoginUser { + + /** + * 编号 + */ + @Id + @Column(columnDefinition = "bigint(64)") + @GeneratedValue(generator = "custom") + @GenericGenerator(name = "custom", strategy = "com.chilunyc.fumao.common.util.jpa.CustomIdentifierGenerator", parameters = {@Parameter(name = "type", value = "Number")}) + private Long id; + + /** + * 名称 + */ + @Column(columnDefinition = "varchar(64) comment '名称'") + private String name; + + /** + * 密码 + */ + @JsonIgnore + @Column(columnDefinition = "varchar(32) comment '密码'") + private String password; + + /** + * 密码 + */ + @Column(columnDefinition = "varchar(32) comment '初始密码'") + private String originPassword; + + /** + * 盐值 + */ + @JsonIgnore + @Column(columnDefinition = "varchar(32) comment '盐值'") + private String salt; + + /** + * 手机号 + */ + @Column(columnDefinition = "varchar(20) comment '手机号'") + private String mobile; + + /** + * 集团 + */ + @Column(columnDefinition = "varchar(64) comment '集团'") + private Long companyId; + + + /** + * 创建时间 + */ + @CreatedDate + @Column(columnDefinition = "datetime comment '创建时间'") + private Date createTime; + + @Fetch(FetchMode.JOIN) + @ManyToOne() + @JoinColumn(name = "companyId", referencedColumnName = "id", insertable = false, updatable = false, foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)) + @NotFound(action = NotFoundAction.IGNORE) + private Company company; + + @Override + public String[] toRoles() { + return new String[]{AuthRoles.CompanyAdmin}; + } + + @Override + public void fromJwt(Claims claims) { + this.id = Long.parseLong(claims.getSubject()); + this.companyId = claims.get("cid", Long.class); + } + + @Override + public void toJwt(JwtBuilder claims) { + claims.setSubject(id.toString()); + claims.claim("cid", companyId); + } +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/model/Place.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/model/Place.java new file mode 100644 index 0000000..cb41521 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/model/Place.java @@ -0,0 +1,157 @@ +package com.chilunyc.fumao.company.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.*; +import org.hibernate.annotations.Parameter; +import org.hibernate.validator.constraints.*; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.ForeignKey; +import javax.validation.constraints.*; + +import javax.persistence.*; +import javax.persistence.Entity; +import javax.persistence.Index; +import javax.persistence.Table; +import java.io.Serializable; +import java.lang.Long; +import java.lang.String; +import java.lang.String; +import java.lang.String; +import java.lang.String; +import java.lang.String; +import java.lang.String; +import java.lang.String; +import java.lang.Long; +import java.lang.String; +import java.lang.String; +import java.lang.Double; +import java.lang.Double; +import java.lang.Double; +import java.util.Date; + +/** + * + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Entity +@Table(name = "fumao_place", indexes = { + @Index(name = "market_companyId", columnList = "companyId"), +}) +@EntityListeners(AuditingEntityListener.class) +public class Place implements Serializable { + + /** + * 编号 + */ + @Id + @Column(columnDefinition = "bigint(64)") + @GeneratedValue(generator = "custom") + @GenericGenerator(name = "custom", strategy = "com.chilunyc.fumao.common.util.jpa.CustomIdentifierGenerator", parameters = {@Parameter(name = "type", value = "Number")}) + private Long id; + + /** + * 名称 + */ + @Column(columnDefinition = "varchar(64) comment '名称'") + private String name; + + /** + * 省份 + */ + @Column(columnDefinition = "varchar(10) comment '省份'") + private String province; + + /** + * 城市 + */ + @Column(columnDefinition = "varchar(10) comment '城市'") + private String city; + + /** + * 城市 + */ + @Column(columnDefinition = "varchar(10) comment '区域'") + private String area; + + /** + * POI + */ + @Column(columnDefinition = "varchar(64) comment 'POI'") + private String poi; + + /** + * 经度 + */ + @Column(columnDefinition = "varchar(12) comment '经度'") + private String lat; + + /** + * 纬度 + */ + @Column(columnDefinition = "varchar(12) comment '纬度'") + private String lng; + + /** + * 地址 + */ + @Column(columnDefinition = "varchar(64) comment '地址'") + private String address; + + /** + * 集团 + */ + @Column(columnDefinition = "varchar(64) comment '集团'") + private Long companyId; + + /** + * 迈外迪 + */ + @Column(columnDefinition = "varchar(128) comment '迈外迪'") + private String maiwaidiId; + + /** + * ETCP + */ + @Column(columnDefinition = "varchar(128) comment 'ETCP'") + private String etcpId; + + /** + * 总面积 + */ + @Column(columnDefinition = "decimal(9,2) comment '总面积'") + private Double totalArea; + + /** + * 营业面积 + */ + @Column(columnDefinition = "decimal(9,2) comment '营业面积'") + private Double sellingArea; + + /** + * 停车场面积 + */ + @Column(columnDefinition = "decimal(9,2) comment '停车场面积'") + private Double depotArea; + + /** + * 创建时间 + */ + @CreatedDate + @Column(columnDefinition = "datetime comment '创建时间'") + private Date createTime; + + + @ManyToOne() + @Fetch(FetchMode.JOIN) + @JoinColumn(name = "companyId", insertable = false, updatable = false, foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)) + @NotFound(action=NotFoundAction.IGNORE) + private Company company; +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/model/PlaceAdmin.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/model/PlaceAdmin.java new file mode 100644 index 0000000..e23f770 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/model/PlaceAdmin.java @@ -0,0 +1,163 @@ +package com.chilunyc.fumao.company.model; + +import com.chilunyc.fumao.common.context.LoginUser; +import com.chilunyc.fumao.common.shiro.AuthRoles; +import com.chilunyc.fumao.company.model.enums.PlaceAdminType; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtBuilder; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.*; +import org.hibernate.annotations.Parameter; + +import org.redisson.mapreduce.Collector; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.*; +import javax.persistence.Entity; +import javax.persistence.ForeignKey; +import javax.persistence.Index; +import javax.persistence.Table; +import java.io.Serializable; +import java.util.Date; +import java.lang.Long; +import java.lang.String; +import java.util.List; +import java.util.stream.Collectors; + +/** + * + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Entity +@Table(name = "fumao_place_admin", indexes = { + @Index(name = "market_admin_mobile", columnList = "mobile"), + @Index(name = "market_admin_placeId", columnList = "placeId"), +}) +@EntityListeners(AuditingEntityListener.class) +public class PlaceAdmin implements Serializable, LoginUser { + + /** + * 编号 + */ + @Id + @Column(columnDefinition = "bigint(64)") + @GeneratedValue(generator = "custom") + @GenericGenerator(name = "custom", strategy = "com.chilunyc.fumao.common.util.jpa.CustomIdentifierGenerator", parameters = {@Parameter(name = "type", value = "Number")}) + private Long id; + + /** + * 名称 + */ + @Column(columnDefinition = "varchar(64) comment '名称'") + private String name; + + /** + * 密码 + */ + @JsonIgnore + @Column(columnDefinition = "varchar(32) comment '密码'") + private String password; + + /** + * 密码 + */ + @Column(columnDefinition = "varchar(32) comment '初始密码'") + private String originPassword; + + /** + * 盐值 + */ + @JsonIgnore + @Column(columnDefinition = "varchar(32) comment '盐值'") + private String salt; + + /** + * 手机号 + */ + @Column(columnDefinition = "varchar(20) comment '手机号'") + private String mobile; + + /** + * 集团 + */ + @Column(columnDefinition = "varchar(64) comment '集团'") + private Long companyId; + + /** + * 集团商场 + */ + @Column(columnDefinition = "varchar(64) comment '集团商场'") + private Long placeId; + + /** + * 类型 + */ + @Column(columnDefinition = "int(1) comment '类型'") + @Enumerated(EnumType.ORDINAL) + private PlaceAdminType type; + + /** + * 角色 + */ + @Column(columnDefinition = "varchar(64) comment '角色'") + private Long placeAdminRoleId; + + /** + * 创建时间 + */ + @CreatedDate + @Column(columnDefinition = "datetime comment '创建时间'") + private Date createTime; + + @Fetch(FetchMode.JOIN) + @ManyToOne() + @JoinColumn(name = "companyId", referencedColumnName = "id", insertable = false, updatable = false, foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)) + @NotFound(action = NotFoundAction.IGNORE) + private Company company; + + @Fetch(FetchMode.JOIN) + @ManyToOne() + @JoinColumn(name = "placeId", referencedColumnName = "id", insertable = false, updatable = false, foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)) + @NotFound(action = NotFoundAction.IGNORE) + private Place place; + + private List placeAdminPermission; + + @Override + public String[] toRoles() { + switch (type) { + // 业务员获取权限 + case Business: + return placeAdminPermission + .stream() + .map(PlaceAdminPermission::getName) + .collect(Collectors.toList()) + .toArray(new String[placeAdminPermission.size()]); + // 管理员所有权限 + default: + return new String[]{AuthRoles.MarketAdmin}; + } + } + + @Override + public void fromJwt(Claims claims) { + this.id = Long.parseLong(claims.getSubject()); + this.companyId = claims.get("cid", Long.class); + this.placeId = claims.get("pid", Long.class); + } + + @Override + public void toJwt(JwtBuilder claims) { + claims.setSubject(this.id.toString()); + claims.claim("cid", this.companyId); + claims.claim("pid", this.placeId); + } +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/model/PlaceAdminPermission.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/model/PlaceAdminPermission.java new file mode 100644 index 0000000..586ef8f --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/model/PlaceAdminPermission.java @@ -0,0 +1,53 @@ +package com.chilunyc.fumao.company.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.*; +import org.hibernate.annotations.Parameter; +import org.hibernate.validator.constraints.*; +import javax.validation.constraints.*; + +import javax.persistence.*; +import javax.persistence.Entity; +import javax.persistence.Index; +import javax.persistence.Table; +import java.io.Serializable; +import java.lang.Long; +import java.lang.String; +import java.util.Date; + +/** +* +*/ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Entity +@Table(name = "fumao_place_admin_permission", indexes = { +}) +public class PlaceAdminPermission implements Serializable { + + /** + * 编号 + */ + @Id + @Column(columnDefinition = "bigint(64)") + @GeneratedValue(generator = "custom") + @GenericGenerator(name = "custom", strategy = "com.chilunyc.fumao.common.util.jpa.CustomIdentifierGenerator", parameters = {@Parameter(name = "type", value = "Number")}) + private Long id; + + /** + * 名称 + */ + @Column(columnDefinition = "varchar(32) comment '名称'") + private String name; + + /** + * 创建时间 + */ + @Column(columnDefinition = "datetime comment '创建时间'") + private Date createTime; +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/model/PlaceFloor.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/model/PlaceFloor.java new file mode 100644 index 0000000..111cd1a --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/model/PlaceFloor.java @@ -0,0 +1,89 @@ +package com.chilunyc.fumao.company.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.*; +import org.hibernate.annotations.Parameter; +import org.hibernate.validator.constraints.*; + +import javax.validation.constraints.*; + +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.*; +import javax.persistence.Entity; +import javax.persistence.Index; +import javax.persistence.Table; +import java.io.Serializable; +import java.util.Date; +import java.lang.Long; +import java.lang.Long; +import java.lang.Integer; +import java.lang.Double; +import java.lang.String; +import java.lang.String; +import java.util.Date; + +/** + * + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Entity +@Table(name = "fumao_place_floor", indexes = { +}) +@EntityListeners(AuditingEntityListener.class) +public class PlaceFloor implements Serializable { + + /** + * 编号 + */ + @Id + @Column(columnDefinition = "bigint(64)") + @GeneratedValue(generator = "custom") + @GenericGenerator(name = "custom", strategy = "com.chilunyc.fumao.common.util.jpa.CustomIdentifierGenerator", parameters = {@Parameter(name = "type", value = "Number")}) + private Long id; + + /** + * 商场 + */ + @Column(columnDefinition = "varchar(64) comment '商场'") + private Long placeId; + + /** + * 楼层 + */ + @Column(columnDefinition = "varchar(2) comment '楼层'") + private Integer floor; + + /** + * 面积 + */ + @Column(columnDefinition = "decimal(9,2) comment '面积'") + private Double area; + + /** + * 平面图 + */ + @Column(columnDefinition = "text comment '平面图'") + private String image; + + /** + * 几座 + */ + @Column(columnDefinition = "varchar(2) comment '几座'") + private String tower; + + + /** + * 创建时间 + */ + @CreatedDate + @Column(columnDefinition = "datetime comment '创建时间'") + private Date createTime; +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/model/ShopApply.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/model/ShopApply.java new file mode 100644 index 0000000..202e692 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/model/ShopApply.java @@ -0,0 +1,80 @@ +package com.chilunyc.fumao.company.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.*; +import org.hibernate.annotations.Parameter; +import org.hibernate.validator.constraints.*; + +import javax.validation.constraints.*; + +import org.springframework.data.jpa.domain.support.AuditingEntityListener; +import org.springframework.data.annotation.CreatedDate; + +import javax.persistence.*; +import javax.persistence.Entity; +import javax.persistence.Index; +import javax.persistence.Table; +import java.io.Serializable; +import java.util.Date; +import java.lang.Long; +import java.lang.String; +import java.lang.String; +import java.lang.String; +import java.lang.String; + +/** + * + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Entity +@Table(name = "fumao_shop_apply", indexes = { +}) +@EntityListeners(AuditingEntityListener.class) +public class ShopApply implements Serializable { + + /** + * 编号 + */ + @Id + @Column(columnDefinition = "bigint(64)") + @GeneratedValue(generator = "custom") + @GenericGenerator(name = "custom", strategy = "com.chilunyc.fumao.common.util.jpa.CustomIdentifierGenerator", parameters = {@Parameter(name = "type", value = "Number")}) + private Long id; + + /** + * 商铺名称 + */ + @Column(columnDefinition = "varchar(64) comment '商铺名称'") + private String name; + + /** + * 申请人 + */ + @Column(columnDefinition = "varchar(64) comment '申请人'") + private String proposer; + + /** + * 手机号 + */ + @Column(columnDefinition = "varchar(20) comment '手机号'") + private String mobile; + + /** + * 备注 + */ + @Column(columnDefinition = "text comment '备注'") + private String market; + + /** + * 创建时间 + */ + @CreatedDate + @Column(columnDefinition = "datetime comment '创建时间'") + private Date createTime; +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/model/enums/PlaceAdminType.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/model/enums/PlaceAdminType.java new file mode 100644 index 0000000..bbd293f --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/model/enums/PlaceAdminType.java @@ -0,0 +1,10 @@ +package com.chilunyc.fumao.company.model.enums; + + +/** +* +*/ +public enum PlaceAdminType { + Manager, + Business, +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/CompanyAdminRepository.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/CompanyAdminRepository.java new file mode 100644 index 0000000..c2e575e --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/CompanyAdminRepository.java @@ -0,0 +1,22 @@ +package com.chilunyc.fumao.company.repository; + +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.company.model.CompanyAdmin; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +/** +* +*/ +public interface CompanyAdminRepository extends JpaRepository, JpaSpecificationExecutor { + + CompanyAdmin findByMobile(String mobile); + + boolean existsByMobile(String mobile); + + CompanyAdmin findByIdAndCompanyId(Long id, Long companyId); + + void deleteByIdAndCompanyId(List request, Long companyId); +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/CompanyRepository.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/CompanyRepository.java new file mode 100644 index 0000000..69e6f88 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/CompanyRepository.java @@ -0,0 +1,12 @@ +package com.chilunyc.fumao.company.repository; + +import com.chilunyc.fumao.company.model.Company; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** +* +*/ +public interface CompanyRepository extends JpaRepository, JpaSpecificationExecutor { + +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/PlaceAdminRepository.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/PlaceAdminRepository.java new file mode 100644 index 0000000..e163261 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/PlaceAdminRepository.java @@ -0,0 +1,23 @@ +package com.chilunyc.fumao.company.repository; + +import com.chilunyc.fumao.company.model.PlaceAdmin; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +/** +* +*/ +public interface PlaceAdminRepository extends JpaRepository, JpaSpecificationExecutor { + + PlaceAdmin findByMobile(String mobile); + + boolean existsByMobile(String mobile); + + List findByPlaceId(Long marketId); + + boolean existsByPlaceId(Long marketId); + + PlaceAdmin findByIdAndCompanyId(Long id, Long companyId); +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/PlaceAdminRoleRepository.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/PlaceAdminRoleRepository.java new file mode 100644 index 0000000..cebbbc4 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/PlaceAdminRoleRepository.java @@ -0,0 +1,12 @@ +package com.chilunyc.fumao.company.repository; + +import com.chilunyc.fumao.company.model.PlaceAdminPermission; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** +* +*/ +public interface PlaceAdminRoleRepository extends JpaRepository, JpaSpecificationExecutor { + +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/PlaceFloorRepository.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/PlaceFloorRepository.java new file mode 100644 index 0000000..7c5d82f --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/PlaceFloorRepository.java @@ -0,0 +1,18 @@ +package com.chilunyc.fumao.company.repository; + +import com.chilunyc.fumao.company.model.PlaceFloor; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +/** +* +*/ +public interface PlaceFloorRepository extends JpaRepository, JpaSpecificationExecutor { + + List findByPlaceId(Long marketId); + + boolean existsByPlaceId(Long marketId); + +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/PlaceRepository.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/PlaceRepository.java new file mode 100644 index 0000000..30f773b --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/PlaceRepository.java @@ -0,0 +1,17 @@ +package com.chilunyc.fumao.company.repository; + +import com.chilunyc.fumao.company.model.Place; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +/** +* +*/ +public interface PlaceRepository extends JpaRepository, JpaSpecificationExecutor { + + List findByCompanyId(Long companyId); + + boolean existsByCompanyId(Long companyId); +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/ShopApplyRepository.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/ShopApplyRepository.java new file mode 100644 index 0000000..4f7fa59 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/repository/ShopApplyRepository.java @@ -0,0 +1,12 @@ +package com.chilunyc.fumao.company.repository; + +import com.chilunyc.fumao.company.model.ShopApply; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** +* +*/ +public interface ShopApplyRepository extends JpaRepository, JpaSpecificationExecutor { + +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/request/.gitkeep b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/request/company/CompanyEditRequest.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/company/CompanyEditRequest.java new file mode 100644 index 0000000..755fa48 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/company/CompanyEditRequest.java @@ -0,0 +1,52 @@ +package com.chilunyc.fumao.company.request.company; + +import com.chilunyc.fumao.company.request.place.PlaceEditRequest; +import com.chilunyc.fumao.company.request.placeAdmin.PlaceAdminEditRequest; +import org.hibernate.validator.constraints.*; + +import javax.validation.constraints.*; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import java.lang.String; +import java.util.List; + +/** + * + */ +@ApiModel +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CompanyEditRequest { + + private Long id; + + @NotBlank(message = "请输入名称") + @ApiModelProperty(value = "名称") + private String name; + + @NotNull(message = "请输入省市区") + @Size(min = 3, message = "请选择省市区") + @ApiModelProperty(value = "省份") + private String[] region; + + @NotBlank(message = "请输入POI") + @ApiModelProperty(value = "POI") + private String poi; + + @NotBlank(message = "请输入经度") + @ApiModelProperty(value = "经度") + private String lat; + + @NotBlank(message = "请输入纬度") + @ApiModelProperty(value = "纬度") + private String lng; + + @NotBlank(message = "请输入地址") + @ApiModelProperty(value = "地址") + private String address; +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/request/company/CompanyPageRequest.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/company/CompanyPageRequest.java new file mode 100644 index 0000000..001d73e --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/company/CompanyPageRequest.java @@ -0,0 +1,14 @@ +package com.chilunyc.fumao.company.request.company; + +import com.chilunyc.fumao.common.request.PageRequest; +import com.chilunyc.fumao.common.util.jpa.query.SortItem; +import com.chilunyc.fumao.common.util.jpa.query.SortItems; +import lombok.Data; + +/** + * + */ +@Data +@SortItems({@SortItem(column = "createTime")}) +public class CompanyPageRequest extends PageRequest { +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/request/companyAdmin/CompanyAdminEditRequest.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/companyAdmin/CompanyAdminEditRequest.java new file mode 100644 index 0000000..da8ee48 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/companyAdmin/CompanyAdminEditRequest.java @@ -0,0 +1,45 @@ +package com.chilunyc.fumao.company.request.companyAdmin; + +import org.hibernate.validator.constraints.*; + +import javax.validation.constraints.*; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import java.lang.Long; +import java.lang.String; +import java.lang.String; +import java.lang.String; +import java.lang.String; +import java.lang.Long; +import java.util.Date; + +/** + * + */ +@ApiModel +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CompanyAdminEditRequest { + + private Long id; + + @NotBlank(message = "请输入名称") + @ApiModelProperty(value = "名称") + private String name; + + @Pattern(regexp = "[\\w\\d]{6,18}", message = "请输入6-18位密码") + @ApiModelProperty(value = "密码") + private String password; + + @Pattern(regexp = "1[\\d]{10}", message = "请输入11位手机号") + @ApiModelProperty(value = "手机号") + private String mobile; + + @ApiModelProperty(value = "集团") + private Long companyId; +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/request/companyAdmin/CompanyAdminPageRequest.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/companyAdmin/CompanyAdminPageRequest.java new file mode 100644 index 0000000..3f31db4 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/companyAdmin/CompanyAdminPageRequest.java @@ -0,0 +1,22 @@ +package com.chilunyc.fumao.company.request.companyAdmin; + +import com.chilunyc.fumao.common.request.PageRequest; +import com.chilunyc.fumao.common.util.jpa.query.QueryItem; +import com.chilunyc.fumao.common.util.jpa.query.QueryType; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.lang.String; + +/** +* +*/ +@Data +public class CompanyAdminPageRequest extends PageRequest { + + @ApiModelProperty(value = "名称") + private String name; + + @QueryItem(type = QueryType.equal) + private Long companyId; +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/request/place/PlaceEditRequest.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/place/PlaceEditRequest.java new file mode 100644 index 0000000..5695540 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/place/PlaceEditRequest.java @@ -0,0 +1,76 @@ +package com.chilunyc.fumao.company.request.place; + +import com.chilunyc.fumao.company.request.placeAdmin.PlaceAdminEditRequest; +import com.chilunyc.fumao.company.request.placeFloor.PlaceFloorEditRequest; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.NotBlank; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.List; + +/** + * + */ +@ApiModel +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlaceEditRequest { + + private Long id; + + @NotBlank(message = "请输入名称") + @ApiModelProperty(value = "名称") + private String name; + + @NotNull(message = "请输入省市区") + @Size(min = 3, message = "请选择省市区") + @ApiModelProperty(value = "省份") + private String[] region; + + @NotBlank(message = "请输入POI") + @ApiModelProperty(value = "POI") + private String poi; + + @NotBlank(message = "请输入经度") + @ApiModelProperty(value = "经度") + private String lat; + + @NotBlank(message = "请输入纬度") + @ApiModelProperty(value = "纬度") + private String lng; + + @NotBlank(message = "请输入地址") + @ApiModelProperty(value = "地址") + private String address; + + @NotNull(message = "请输入集团") + @ApiModelProperty(value = "集团") + private Long companyId; + + @ApiModelProperty(value = "迈外迪") + private String maiwaidId; + + @ApiModelProperty(value = "ETCP") + private String etcpId; + + @ApiModelProperty(value = "总面积") + private Double totalArea; + + @ApiModelProperty(value = "营业面积") + private Double sellingArea; + + @ApiModelProperty(value = "停车场面积") + private Double depotArea; + + private List placeFloorList; + + private List placeAdminList; +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/request/place/PlacePageRequest.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/place/PlacePageRequest.java new file mode 100644 index 0000000..fc2249a --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/place/PlacePageRequest.java @@ -0,0 +1,19 @@ +package com.chilunyc.fumao.company.request.place; + +import com.chilunyc.fumao.common.request.PageRequest; +import com.chilunyc.fumao.common.util.jpa.query.QueryItem; +import com.chilunyc.fumao.common.util.jpa.query.QueryType; +import com.chilunyc.fumao.common.util.jpa.query.SortItem; +import com.chilunyc.fumao.common.util.jpa.query.SortItems; +import lombok.Data; + +/** +* +*/ +@Data +@SortItems({@SortItem(column = "createTime")}) +public class PlacePageRequest extends PageRequest { + + @QueryItem(type = QueryType.equal) + private Long companyId; +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/request/placeAdmin/PlaceAdminEditRequest.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/placeAdmin/PlaceAdminEditRequest.java new file mode 100644 index 0000000..becef5b --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/placeAdmin/PlaceAdminEditRequest.java @@ -0,0 +1,49 @@ +package com.chilunyc.fumao.company.request.placeAdmin; + +import com.chilunyc.fumao.company.model.enums.PlaceAdminType; +import org.hibernate.validator.constraints.*; + +import javax.validation.constraints.*; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import java.lang.Long; +import java.lang.String; + +/** + * + */ +@ApiModel +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlaceAdminEditRequest { + + private Long id; + + @NotBlank(message = "请输入名称") + @ApiModelProperty(value = "名称") + private String name; + + @NotBlank(message = "请输入密码") + @Pattern(regexp = "[\\w\\d]{6,18}", message = "长度6-18位的字母数字") + @ApiModelProperty(value = "密码") + private String password; + + @Pattern(regexp = "1[\\d]{10}", message = "请输入11位手机号") + @ApiModelProperty(value = "手机号") + private String mobile; + + @ApiModelProperty(value = "集团") + private Long companyId; + + @NotNull(message = "请选择商场") + @ApiModelProperty(value = "集团商场") + private Long placeId; + + private PlaceAdminType placeAdminType; + +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/request/placeAdmin/PlaceAdminPageRequest.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/placeAdmin/PlaceAdminPageRequest.java new file mode 100644 index 0000000..f574887 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/placeAdmin/PlaceAdminPageRequest.java @@ -0,0 +1,23 @@ +package com.chilunyc.fumao.company.request.placeAdmin; + +import com.chilunyc.fumao.common.request.PageRequest; +import com.chilunyc.fumao.common.util.jpa.query.QueryItem; +import com.chilunyc.fumao.common.util.jpa.query.QueryType; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.lang.Long; +import java.lang.String; + +/** + * + */ +@Data +public class PlaceAdminPageRequest extends PageRequest { + + @QueryItem(type = QueryType.equal) + private Long placeId; + + @QueryItem(type = QueryType.equal) + private Long companyId; +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/request/placeFloor/PlaceFloorEditRequest.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/placeFloor/PlaceFloorEditRequest.java new file mode 100644 index 0000000..b8c1401 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/placeFloor/PlaceFloorEditRequest.java @@ -0,0 +1,41 @@ +package com.chilunyc.fumao.company.request.placeFloor; + +import org.hibernate.validator.constraints.*; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import java.lang.Long; +import java.lang.Integer; +import java.lang.Double; +import java.lang.String; + +/** + * + */ +@ApiModel +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlaceFloorEditRequest { + + private String id; + + @NotBlank(message = "请输入商场") + @ApiModelProperty(value = "商场") + private Long placeId; + + @ApiModelProperty(value = "楼层") + private Integer floor; + + @ApiModelProperty(value = "面积") + private Double area; + + @ApiModelProperty(value = "平面图") + private String image; + + @ApiModelProperty(value = "几座") + private String tower; +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/request/placeFloor/PlaceFloorPageRequest.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/placeFloor/PlaceFloorPageRequest.java new file mode 100644 index 0000000..2a0935b --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/placeFloor/PlaceFloorPageRequest.java @@ -0,0 +1,20 @@ +package com.chilunyc.fumao.company.request.placeFloor; + +import com.chilunyc.fumao.common.request.PageRequest; +import com.chilunyc.fumao.common.util.jpa.query.QueryItem; +import com.chilunyc.fumao.common.util.jpa.query.QueryType; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.lang.Long; + +/** +* +*/ +@Data +public class PlaceFloorPageRequest extends PageRequest { + + @ApiModelProperty(value = "商场") + @QueryItem(type = QueryType.equal) + private Long placeId; +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/request/shopApply/ShopApplyEditRequest.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/shopApply/ShopApplyEditRequest.java new file mode 100644 index 0000000..5dea45b --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/shopApply/ShopApplyEditRequest.java @@ -0,0 +1,44 @@ +package com.chilunyc.fumao.company.request.shopApply; + +import org.hibernate.validator.constraints.*; + +import javax.validation.constraints.*; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import java.lang.Long; +import java.lang.String; +import java.lang.String; +import java.lang.String; +import java.lang.String; + +/** + * + */ +@ApiModel +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ShopApplyEditRequest { + + private String id; + + + @NotBlank(message = "请输入商铺名称") + @ApiModelProperty(value = "商铺名称") + private String name; + + @NotBlank(message = "请输入申请人") + @ApiModelProperty(value = "申请人") + private String proposer; + + @Pattern(regexp = "1[\\d]{10}", message = "请输入11位手机号") + @ApiModelProperty(value = "手机号") + private String mobile; + + @ApiModelProperty(value = "备注") + private String market; +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/request/shopApply/ShopApplyPageRequest.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/shopApply/ShopApplyPageRequest.java new file mode 100644 index 0000000..94895e8 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/request/shopApply/ShopApplyPageRequest.java @@ -0,0 +1,11 @@ +package com.chilunyc.fumao.company.request.shopApply; + +import com.chilunyc.fumao.common.request.PageRequest; +import lombok.Data; + +/** +* +*/ +@Data +public class ShopApplyPageRequest extends PageRequest { +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/response/.gitkeep b/fumao-company/src/main/java/com/chilunyc/fumao/company/response/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/service/CompanyAdminService.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/service/CompanyAdminService.java new file mode 100644 index 0000000..e3264ea --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/service/CompanyAdminService.java @@ -0,0 +1,113 @@ +package com.chilunyc.fumao.company.service; + +import com.chilunyc.fumao.common.context.RequestHolder; +import com.chilunyc.fumao.common.exception.SystemException; +import com.chilunyc.fumao.common.log.model.EventTarget; +import com.chilunyc.fumao.common.log.model.EventType; +import com.chilunyc.fumao.common.log.service.EventService; +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.request.LoginRequest; +import com.chilunyc.fumao.common.util.BeanHelper; +import com.chilunyc.fumao.common.util.jpa.query.QueryBuilder; +import com.chilunyc.fumao.common.util.security.SaltHelper; +import com.chilunyc.fumao.company.model.Company; +import com.chilunyc.fumao.company.model.CompanyAdmin; +import com.chilunyc.fumao.company.repository.CompanyAdminRepository; +import com.chilunyc.fumao.company.request.companyAdmin.CompanyAdminEditRequest; +import com.chilunyc.fumao.company.request.companyAdmin.CompanyAdminPageRequest; +import com.chilunyc.fumao.company.request.placeAdmin.PlaceAdminEditRequest; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * + */ +@Log4j +@Service +@Transactional +public class CompanyAdminService { + + + @Autowired + private CompanyAdminRepository companyAdminRepository; + + @Autowired + private EventService eventService; + + public Page page(CompanyAdminPageRequest request) { + return companyAdminRepository.findAll(QueryBuilder.build(request), request.getPage()); + } + + + public CompanyAdmin find(Long id) { + CompanyAdmin one = companyAdminRepository.findOne(id); + return one; + } + + + public CompanyAdmin edit(CompanyAdminEditRequest request) { + if (request.getId() == null && + companyAdminRepository.existsByMobile(request.getMobile())) { + throw new SystemException("100000"); + } + + CompanyAdmin companyAdmin = new CompanyAdmin(); + BeanHelper.copyProperties(companyAdmin, request); + String salt = SaltHelper.salt(); + companyAdmin.setOriginPassword(request.getPassword()); + companyAdmin.setSalt(salt); + companyAdmin.setPassword(SaltHelper.exec(request.getPassword(), salt)); + companyAdmin = companyAdminRepository.save(companyAdmin); + eventService.add(RequestHolder.get(), EventTarget.System, EventType.编辑集团管理员, companyAdmin.getId(), request); + return companyAdmin; + } + + public void remove(IdsRequest request) { + request + .getIds() + .forEach((id) -> { + companyAdminRepository.delete(id); + }); + eventService.add(RequestHolder.get(), EventTarget.System, EventType.删除集团管理员, null, request.getIds()); + } + + + public List all(CompanyAdminPageRequest request) { + if (request == null) { + request = new CompanyAdminPageRequest(); + } + List all = companyAdminRepository.findAll(QueryBuilder.build(request)); + return all; + } + + + public CompanyAdmin login(LoginRequest request) { + CompanyAdmin companyAdmin = companyAdminRepository.findByMobile(request.getMobile()); + if (companyAdmin != null && + SaltHelper.isEquals(companyAdmin.getPassword(), request.getPassword(), companyAdmin.getSalt())) { + return companyAdmin; + } + throw new SystemException("000004"); + } + + public CompanyAdmin findByCompanyId(Long id, Long companyId) { + return companyAdminRepository.findByIdAndCompanyId(id, companyId); + } + + public void removeByCompanyId(IdsRequest request, Long companyId) { + companyAdminRepository.deleteByIdAndCompanyId(request.getIds(), companyId); + } + + public void resetPassword(Long id, Long companyId) { + CompanyAdmin companyAdmin = companyAdminRepository.findByIdAndCompanyId(id, companyId); + if (companyAdmin != null) { + companyAdmin.setPassword(SaltHelper.exec(companyAdmin.getOriginPassword(), companyAdmin.getSalt())); + companyAdminRepository.save(companyAdmin); + } + } +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/service/CompanyService.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/service/CompanyService.java new file mode 100644 index 0000000..8574306 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/service/CompanyService.java @@ -0,0 +1,89 @@ +package com.chilunyc.fumao.company.service; + +import com.chilunyc.fumao.common.context.RequestHolder; +import com.chilunyc.fumao.common.log.model.EventTarget; +import com.chilunyc.fumao.common.log.model.EventType; +import com.chilunyc.fumao.common.log.service.EventService; +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.util.BeanHelper; +import com.chilunyc.fumao.common.util.jpa.query.QueryBuilder; +import com.chilunyc.fumao.company.model.Company; +import com.chilunyc.fumao.company.repository.CompanyRepository; +import com.chilunyc.fumao.company.request.company.CompanyEditRequest; +import com.chilunyc.fumao.company.request.company.CompanyPageRequest; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * + */ +@Log4j +@Service +@Transactional +public class CompanyService { + + + @Autowired + private CompanyRepository companyRepository; + + @Autowired + private EventService eventService; + + @Autowired + private PlaceService placeService; + + @Autowired + private CompanyAdminService companyAdminService; + + public Page page(CompanyPageRequest request) { + return companyRepository.findAll(QueryBuilder.build(request), request.getPage()); + } + + + public Company find(Long id) { + Company one = companyRepository.findOne(id); + return one; + } + + + public Company edit(CompanyEditRequest request) { + Company company = new Company(); + BeanHelper.copyProperties(company, request); + String[] region = request.getRegion(); + company.setProvince(region[0]); + company.setCity(region[1]); + company.setArea(region[2]); + company = companyRepository.save(company); + + + // 调用flyway, 创建一个数据库实例 + + eventService.add(RequestHolder.get(), EventTarget.System, EventType.编辑集团, company.getId(), request); + return company; + } + + public void remove(IdsRequest request) { + request + .getIds() + .forEach((id) -> { + companyRepository.delete(id); + }); + eventService.add(RequestHolder.get(), EventTarget.System, EventType.删除集团, null, request.getIds()); + } + + + public List all(CompanyPageRequest request) { + if (request == null) { + request = new CompanyPageRequest(); + } + List all = companyRepository.findAll(QueryBuilder.build(request)); + return all; + } + + +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/service/PlaceAdminRoleService.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/service/PlaceAdminRoleService.java new file mode 100644 index 0000000..8bc60ea --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/service/PlaceAdminRoleService.java @@ -0,0 +1,59 @@ +package com.chilunyc.fumao.company.service; + +import com.chilunyc.fumao.common.context.RequestHolder; +import com.chilunyc.fumao.common.log.model.EventTarget; +import com.chilunyc.fumao.common.log.model.EventType; +import com.chilunyc.fumao.common.log.service.EventService; +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.request.PageRequest; +import com.chilunyc.fumao.company.model.PlaceAdminPermission; +import com.chilunyc.fumao.company.repository.PlaceAdminRoleRepository; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * + */ +@Log4j +@Service +@Transactional +public class PlaceAdminRoleService { + + + @Autowired + private PlaceAdminRoleRepository placeAdminRoleRepository; + + @Autowired + private EventService eventService; + + public Page page(PageRequest request) { + return placeAdminRoleRepository.findAll(request.getPage()); + } + + + public PlaceAdminPermission find(Long id) { + PlaceAdminPermission one = placeAdminRoleRepository.findOne(id); + return one; + } + + + public PlaceAdminPermission edit(PlaceAdminPermission request) { + request = placeAdminRoleRepository.save(request); + eventService.add(RequestHolder.get(), EventTarget.Company, EventType.编辑商场管理员角色, request.getId(), request); + return request; + } + + public void remove(IdsRequest request) { + request + .getIds() + .forEach((id) -> { + placeAdminRoleRepository.delete(id); + }); + eventService.add(RequestHolder.get(), EventTarget.Company, EventType.删除商场管理员角色, null, request.getIds()); + } + + +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/service/PlaceAdminService.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/service/PlaceAdminService.java new file mode 100644 index 0000000..d572776 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/service/PlaceAdminService.java @@ -0,0 +1,105 @@ +package com.chilunyc.fumao.company.service; + +import com.chilunyc.fumao.common.context.RequestHolder; +import com.chilunyc.fumao.common.exception.SystemException; +import com.chilunyc.fumao.common.log.model.EventTarget; +import com.chilunyc.fumao.common.log.model.EventType; +import com.chilunyc.fumao.common.log.service.EventService; +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.request.LoginRequest; +import com.chilunyc.fumao.common.util.BeanHelper; +import com.chilunyc.fumao.common.util.jpa.query.QueryBuilder; +import com.chilunyc.fumao.common.util.security.SaltHelper; +import com.chilunyc.fumao.company.model.Place; +import com.chilunyc.fumao.company.model.PlaceAdmin; +import com.chilunyc.fumao.company.repository.PlaceAdminRepository; +import com.chilunyc.fumao.company.request.placeAdmin.PlaceAdminEditRequest; +import com.chilunyc.fumao.company.request.placeAdmin.PlaceAdminPageRequest; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * + */ +@Log4j +@Service +@Transactional +public class PlaceAdminService { + + + @Autowired + private PlaceAdminRepository placeAdminRepository; + + @Autowired + private EventService eventService; + + public Page page(PlaceAdminPageRequest request) { + return placeAdminRepository.findAll(QueryBuilder.build(request), request.getPage()); + } + + + public PlaceAdmin find(Long id) { + PlaceAdmin one = placeAdminRepository.findOne(id); + return one; + } + + + public PlaceAdmin edit(PlaceAdminEditRequest request) { + if (request.getId() == null && + placeAdminRepository.existsByMobile(request.getMobile())) { + throw new SystemException("100000"); + } + + PlaceAdmin placeAdmin = new PlaceAdmin(); + String salt = SaltHelper.salt(); + BeanHelper.copyProperties(placeAdmin, request); + placeAdmin.setOriginPassword(request.getPassword()); + placeAdmin.setSalt(salt); + placeAdmin.setPassword(SaltHelper.exec(request.getPassword(), salt)); + placeAdmin.setType(request.getPlaceAdminType()); + placeAdmin = placeAdminRepository.save(placeAdmin); + eventService.add(RequestHolder.get(), EventTarget.System, EventType.编辑商场管理员, placeAdmin.getId(), request); + return placeAdmin; + } + + public void remove(IdsRequest request) { + request + .getIds() + .forEach((id) -> { + placeAdminRepository.delete(id); + }); + eventService.add(RequestHolder.get(), EventTarget.System, EventType.删除商场管理员, null, request.getIds()); + } + + public void edit(Place place, List placeAdminList) { + placeAdminList + .stream() + .peek(placeAdminEditRequest -> { + placeAdminEditRequest.setPlaceId(place.getId()); + placeAdminEditRequest.setCompanyId(place.getCompanyId()); + }) + .forEach(this::edit); + } + + public void resetPassword(Long id, Long companyId) { + PlaceAdmin placeAdmin = placeAdminRepository.findByIdAndCompanyId(id, companyId); + if (placeAdmin != null) { + placeAdmin.setPassword(SaltHelper.exec(placeAdmin.getOriginPassword(), placeAdmin.getSalt())); + placeAdminRepository.save(placeAdmin); + } + } + + public PlaceAdmin login(LoginRequest request) { + PlaceAdmin placeAdmin = placeAdminRepository.findByMobile(request.getMobile()); + if (placeAdmin != null && + SaltHelper.isEquals(placeAdmin.getPassword(), request.getPassword(), placeAdmin.getSalt())) { + return placeAdmin; + } + throw new SystemException("000004"); + } +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/service/PlaceFloorService.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/service/PlaceFloorService.java new file mode 100644 index 0000000..cbdde22 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/service/PlaceFloorService.java @@ -0,0 +1,76 @@ +package com.chilunyc.fumao.company.service; + +import com.chilunyc.fumao.common.context.RequestHolder; +import com.chilunyc.fumao.common.log.model.EventTarget; +import com.chilunyc.fumao.common.log.model.EventType; +import com.chilunyc.fumao.common.log.service.EventService; +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.util.BeanHelper; +import com.chilunyc.fumao.common.util.jpa.query.QueryBuilder; +import com.chilunyc.fumao.company.model.Place; +import com.chilunyc.fumao.company.model.PlaceFloor; +import com.chilunyc.fumao.company.repository.PlaceFloorRepository; +import com.chilunyc.fumao.company.request.placeFloor.PlaceFloorEditRequest; +import com.chilunyc.fumao.company.request.placeFloor.PlaceFloorPageRequest; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * + */ +@Log4j +@Service +@Transactional +public class PlaceFloorService { + + + @Autowired + private PlaceFloorRepository placeFloorRepository; + + @Autowired + private EventService eventService; + + public Page page(PlaceFloorPageRequest request) { + return placeFloorRepository.findAll(QueryBuilder.build(request), request.getPage()); + } + + + public PlaceFloor find(Long id) { + PlaceFloor one = placeFloorRepository.findOne(id); + return one; + } + + + public PlaceFloor edit(PlaceFloorEditRequest request) { + PlaceFloor placeFloor = new PlaceFloor(); + BeanHelper.copyProperties(placeFloor, request); + placeFloor = placeFloorRepository.save(placeFloor); + eventService.add(RequestHolder.get(), EventTarget.System, EventType.编辑商场楼层, placeFloor.getId(), request); + return placeFloor; + } + + public void remove(IdsRequest request) { + request + .getIds() + .forEach((id) -> { + placeFloorRepository.delete(id); + }); + eventService.add(RequestHolder.get(), EventTarget.System, EventType.删除商场楼层, null, request.getIds()); + } + + + public void edit(Place place, List placeFloorList) { + placeFloorList.stream() + .peek(placeFloor -> placeFloor.setPlaceId(place.getId())) + .forEach(this::edit); + } + + public List all(PlaceFloorPageRequest request) { + return placeFloorRepository.findAll(QueryBuilder.build(request)); + } +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/service/PlaceService.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/service/PlaceService.java new file mode 100644 index 0000000..98f849b --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/service/PlaceService.java @@ -0,0 +1,104 @@ +package com.chilunyc.fumao.company.service; + +import com.chilunyc.fumao.common.context.RequestHolder; +import com.chilunyc.fumao.common.log.model.EventTarget; +import com.chilunyc.fumao.common.log.model.EventType; +import com.chilunyc.fumao.common.log.service.EventService; +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.util.BeanHelper; +import com.chilunyc.fumao.common.util.jpa.query.QueryBuilder; +import com.chilunyc.fumao.company.model.Place; +import com.chilunyc.fumao.company.repository.PlaceFloorRepository; +import com.chilunyc.fumao.company.repository.PlaceRepository; +import com.chilunyc.fumao.company.request.place.PlaceEditRequest; +import com.chilunyc.fumao.company.request.place.PlacePageRequest; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * + */ +@Log4j +@Service +@Transactional +public class PlaceService { + + + @Autowired + private PlaceRepository placeRepository; + + @Autowired + private PlaceFloorRepository placeFloorRepository; + + @Autowired + private EventService eventService; + + @Autowired + private PlaceFloorService placeFloorService; + + @Autowired + private PlaceAdminService placeAdminService; + + public Page page(PlacePageRequest request) { + return placeRepository.findAll(QueryBuilder.build(request), request.getPage()); + } + + + public Place find(Long id) { + Place one = placeRepository.findOne(id); + return one; + } + + + public Place edit(PlaceEditRequest request) { + Place place = new Place(); + BeanHelper.copyProperties(place, request); + String[] region = request.getRegion(); + place.setProvince(region[0]); + place.setCity(region[1]); + place.setArea(region[2]); + place = placeRepository.save(place); + + // 处理楼层, 全部清掉, 冲洗加 + if (request.getPlaceFloorList() != null) { + placeFloorRepository.deleteAllInBatch(); + placeFloorService.edit(place, request.getPlaceFloorList()); + } + + // 处理管理员 + if (request.getPlaceAdminList() != null) { + placeAdminService.edit(place, request.getPlaceAdminList()); + } + + eventService.add(RequestHolder.get(), EventTarget.System, EventType.编辑商场, place.getId(), request); + return place; + } + + public void remove(IdsRequest request) { + request + .getIds() + .forEach((id) -> { + placeRepository.delete(id); + }); + eventService.add(RequestHolder.get(), EventTarget.System, EventType.删除商场, null, request.getIds()); + } + + + public List all(PlacePageRequest request) { + if (request == null) { + request = new PlacePageRequest(); + } + List all = placeRepository.findAll(QueryBuilder.build(request)); + return all; + } + + + public void edit(List marketList) { + marketList.forEach(this::edit); + } +} diff --git a/fumao-company/src/main/java/com/chilunyc/fumao/company/service/ShopApplyService.java b/fumao-company/src/main/java/com/chilunyc/fumao/company/service/ShopApplyService.java new file mode 100644 index 0000000..786e023 --- /dev/null +++ b/fumao-company/src/main/java/com/chilunyc/fumao/company/service/ShopApplyService.java @@ -0,0 +1,62 @@ +package com.chilunyc.fumao.company.service; + +import com.chilunyc.fumao.common.context.RequestHolder; +import com.chilunyc.fumao.common.log.model.EventTarget; +import com.chilunyc.fumao.common.log.model.EventType; +import com.chilunyc.fumao.common.log.service.EventService; +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.util.jpa.query.QueryBuilder; +import com.chilunyc.fumao.company.model.ShopApply; +import com.chilunyc.fumao.company.repository.ShopApplyRepository; +import com.chilunyc.fumao.company.request.shopApply.ShopApplyEditRequest; +import com.chilunyc.fumao.company.request.shopApply.ShopApplyPageRequest; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * + */ +@Log4j +@Service +@Transactional +public class ShopApplyService { + + + @Autowired + private ShopApplyRepository shopApplyRepository; + + @Autowired + private EventService eventService; + + public Page page(ShopApplyPageRequest request) { + return shopApplyRepository.findAll(QueryBuilder.build(request), request.getPage()); + } + + + public ShopApply find(Long id) { + ShopApply one = shopApplyRepository.findOne(id); + return one; + } + + + public ShopApply edit(ShopApplyEditRequest request) { + ShopApply shopApply = new ShopApply(); + shopApply = shopApplyRepository.save(shopApply); + eventService.add(RequestHolder.get(), EventTarget.Company, EventType.编辑商铺申请, shopApply.getId(), request); + return shopApply; + } + + public void remove(IdsRequest request) { + request + .getIds() + .forEach((id) -> { + shopApplyRepository.delete(id); + }); + eventService.add(RequestHolder.get(), EventTarget.Company, EventType.删除商铺申请, null, request.getIds()); + } + + +} diff --git a/fumao-company/src/main/resources/com/chilunyc/fumao/company/repository/.gitkeep b/fumao-company/src/main/resources/com/chilunyc/fumao/company/repository/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/fumao-service/pom.xml b/fumao-service/pom.xml new file mode 100644 index 0000000..bb76861 --- /dev/null +++ b/fumao-service/pom.xml @@ -0,0 +1,32 @@ + + + + fumao + com.aki + 0.0.1-SNAPSHOT + + 4.0.0 + + fumao-service + + + + + com.aki + fumao-common + 0.0.1-SNAPSHOT + + + com.aki + fumao-system + ${project.version} + + + com.aki + fumao-company + ${project.version} + + + \ No newline at end of file diff --git a/fumao-service/src/main/java/com/chilunyc/fumao/service/model/.gitkeep b/fumao-service/src/main/java/com/chilunyc/fumao/service/model/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/fumao-service/src/main/java/com/chilunyc/fumao/service/repository/.gitkeep b/fumao-service/src/main/java/com/chilunyc/fumao/service/repository/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/fumao-service/src/main/java/com/chilunyc/fumao/service/request/.gitkeep b/fumao-service/src/main/java/com/chilunyc/fumao/service/request/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/fumao-service/src/main/java/com/chilunyc/fumao/service/response/.gitkeep b/fumao-service/src/main/java/com/chilunyc/fumao/service/response/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/fumao-service/src/main/java/com/chilunyc/fumao/service/service/.gitkeep b/fumao-service/src/main/java/com/chilunyc/fumao/service/service/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/fumao-service/src/main/resources/com/chilunyc/fumao/service/repository/.gitkeep b/fumao-service/src/main/resources/com/chilunyc/fumao/service/repository/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/fumao-system/pom.xml b/fumao-system/pom.xml new file mode 100644 index 0000000..f58dbcf --- /dev/null +++ b/fumao-system/pom.xml @@ -0,0 +1,22 @@ + + + + fumao + com.aki + 0.0.1-SNAPSHOT + + 4.0.0 + + fumao-system + + + + + com.aki + fumao-common + 0.0.1-SNAPSHOT + + + \ No newline at end of file diff --git a/fumao-system/src/main/java/com/chilunyc/fumao/system/model/SystemAdmin.java b/fumao-system/src/main/java/com/chilunyc/fumao/system/model/SystemAdmin.java new file mode 100644 index 0000000..b786e58 --- /dev/null +++ b/fumao-system/src/main/java/com/chilunyc/fumao/system/model/SystemAdmin.java @@ -0,0 +1,88 @@ +package com.chilunyc.fumao.system.model; + +import com.chilunyc.fumao.common.context.LoginUser; +import com.chilunyc.fumao.common.shiro.AuthRoles; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtBuilder; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.Parameter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.*; +import java.io.Serializable; +import java.util.Date; + +/** + * + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Entity +@Table(name = "fumao_system_admin", indexes = { + @Index(name = "system_admin_mobile", columnList = "mobile") +}) +@EntityListeners(AuditingEntityListener.class) +public class SystemAdmin implements Serializable, LoginUser { + + /** + * 编号 + */ + @Id + @Column(length = 64) + @GeneratedValue(generator = "custom") + @GenericGenerator(name = "custom", strategy = "com.chilunyc.fumao.common.util.jpa.CustomIdentifierGenerator", parameters = {@Parameter(name = "type", value = "Number")}) + private Long id; + + /** + * 名称 + */ + @Column(columnDefinition = "varchar(64) comment '名称'") + private String name; + + /** + * 密码 + */ + @Column(columnDefinition = "varchar(32) comment '密码'") + private String password; + + /** + * 盐值 + */ + @Column(columnDefinition = "varchar(32) comment '盐值'") + private String salt; + + /** + * 手机号 + */ + @Column(columnDefinition = "varchar(20) comment '手机号'") + private String mobile; + + /** + * 创建时间 + */ + @CreatedDate + @Column(columnDefinition = "datetime comment '创建时间'") + private Date createTime; + + @Override + public String[] toRoles() { + return new String[]{AuthRoles.SystemAdmin}; + } + + @Override + public void fromJwt(Claims claims) { + this.id = Long.parseLong(claims.getSubject()); + } + + @Override + public void toJwt(JwtBuilder claims) { + claims.setSubject(id.toString()); + } +} diff --git a/fumao-system/src/main/java/com/chilunyc/fumao/system/repository/SystemAdminRepository.java b/fumao-system/src/main/java/com/chilunyc/fumao/system/repository/SystemAdminRepository.java new file mode 100644 index 0000000..e199619 --- /dev/null +++ b/fumao-system/src/main/java/com/chilunyc/fumao/system/repository/SystemAdminRepository.java @@ -0,0 +1,16 @@ +package com.chilunyc.fumao.system.repository; + +import com.chilunyc.fumao.system.model.SystemAdmin; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** + * + */ +public interface SystemAdminRepository extends JpaRepository, JpaSpecificationExecutor { + + SystemAdmin findByMobile(String mobile); + + boolean existsByMobile(String mobile); + +} diff --git a/fumao-system/src/main/java/com/chilunyc/fumao/system/request/.gitkeep b/fumao-system/src/main/java/com/chilunyc/fumao/system/request/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/fumao-system/src/main/java/com/chilunyc/fumao/system/request/systemAdmin/SystemAdminEditRequest.java b/fumao-system/src/main/java/com/chilunyc/fumao/system/request/systemAdmin/SystemAdminEditRequest.java new file mode 100644 index 0000000..4534dd6 --- /dev/null +++ b/fumao-system/src/main/java/com/chilunyc/fumao/system/request/systemAdmin/SystemAdminEditRequest.java @@ -0,0 +1,38 @@ +package com.chilunyc.fumao.system.request.systemAdmin; + +import org.hibernate.validator.constraints.*; +import javax.validation.constraints.*; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import java.lang.Long; +import java.lang.String; +import java.lang.String; +import java.lang.String; +import java.lang.String; + +/** +* +*/ +@ApiModel +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class SystemAdminEditRequest { + + private String id; + + + @NotBlank(message = "请输入名称") + @ApiModelProperty(value = "名称") + private String name; + + @Pattern(regexp = "[\\w]{6,18}", message = "请输入6-18位密码") + @ApiModelProperty(value = "密码") + private String password; + + @Pattern(regexp = "1[\\d]{10}", message = "请输入11位手机号") + @ApiModelProperty(value = "手机号") + private String mobile; +} diff --git a/fumao-system/src/main/java/com/chilunyc/fumao/system/request/systemAdmin/SystemAdminPageRequest.java b/fumao-system/src/main/java/com/chilunyc/fumao/system/request/systemAdmin/SystemAdminPageRequest.java new file mode 100644 index 0000000..deecadf --- /dev/null +++ b/fumao-system/src/main/java/com/chilunyc/fumao/system/request/systemAdmin/SystemAdminPageRequest.java @@ -0,0 +1,17 @@ +package com.chilunyc.fumao.system.request.systemAdmin; + +import com.chilunyc.fumao.common.request.PageRequest; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.lang.String; + +/** +* +*/ +@Data +public class SystemAdminPageRequest extends PageRequest { + + @ApiModelProperty(value = "名称") + private String name; +} diff --git a/fumao-system/src/main/java/com/chilunyc/fumao/system/response/.gitkeep b/fumao-system/src/main/java/com/chilunyc/fumao/system/response/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/fumao-system/src/main/java/com/chilunyc/fumao/system/service/SystemAdminService.java b/fumao-system/src/main/java/com/chilunyc/fumao/system/service/SystemAdminService.java new file mode 100644 index 0000000..bf98a55 --- /dev/null +++ b/fumao-system/src/main/java/com/chilunyc/fumao/system/service/SystemAdminService.java @@ -0,0 +1,93 @@ +package com.chilunyc.fumao.system.service; + +import com.chilunyc.fumao.common.context.RequestHolder; +import com.chilunyc.fumao.common.exception.SystemException; +import com.chilunyc.fumao.common.log.model.EventTarget; +import com.chilunyc.fumao.common.log.model.EventType; +import com.chilunyc.fumao.common.log.service.EventService; +import com.chilunyc.fumao.common.request.IdsRequest; +import com.chilunyc.fumao.common.request.LoginRequest; +import com.chilunyc.fumao.common.util.jpa.query.QueryBuilder; +import com.chilunyc.fumao.common.util.security.SaltHelper; +import com.chilunyc.fumao.system.model.SystemAdmin; +import com.chilunyc.fumao.system.repository.SystemAdminRepository; +import com.chilunyc.fumao.system.request.systemAdmin.SystemAdminEditRequest; +import com.chilunyc.fumao.system.request.systemAdmin.SystemAdminPageRequest; +import lombok.extern.log4j.Log4j; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * + */ +@Log4j +@Service +@Transactional +public class SystemAdminService implements InitializingBean { + + + @Autowired + private SystemAdminRepository systemAdminRepository; + + @Autowired + private EventService eventService; + + public Page page(SystemAdminPageRequest request) { + return systemAdminRepository.findAll(QueryBuilder.build(request), request.getPage()); + } + + + public SystemAdmin find(Long id) { + SystemAdmin one = systemAdminRepository.findOne(id); + return one; + } + + + public SystemAdmin edit(SystemAdminEditRequest request) { + SystemAdmin systemAdmin = new SystemAdmin(); + systemAdmin = systemAdminRepository.save(systemAdmin); + eventService.add(RequestHolder.get(), EventTarget.System, EventType.编辑系统管理员, systemAdmin.getId(), request); + return systemAdmin; + } + + public void remove(IdsRequest request) { + request + .getIds() + .forEach((id) -> { + systemAdminRepository.delete(id); + }); + eventService.add(RequestHolder.get(), EventTarget.System, EventType.删除系统管理员, null, request.getIds()); + } + + + @Override + public void afterPropertiesSet() throws Exception { + if (systemAdminRepository.existsByMobile("13888888888")) { + return; + } + String salt = SaltHelper.salt(); + systemAdminRepository.save( + SystemAdmin + .builder() + .mobile("13888888888") + .name("Tkk") + .salt(salt) + .password(SaltHelper.exec("!admin123", salt)) + .build() + ); + } + + public SystemAdmin login(LoginRequest request) { + SystemAdmin systemAdmin = systemAdminRepository.findByMobile(request.getMobile()); + if (systemAdmin == null) { + throw new SystemException("000004"); + } else if (SaltHelper.isEquals(systemAdmin.getPassword(), request.getPassword(), systemAdmin.getSalt())) { + return systemAdmin; + } else { + throw new SystemException("000004"); + } + } +} diff --git a/fumao-system/src/main/resources/com/chilunyc/fumao/system/repository/.gitkeep b/fumao-system/src/main/resources/com/chilunyc/fumao/system/repository/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..f403325 --- /dev/null +++ b/pom.xml @@ -0,0 +1,106 @@ + + + 4.0.0 + + com.aki + fumao + 0.0.1-SNAPSHOT + + fumao-app + fumao-common + fumao-service + fumao-system + fumao-company + + pom + + fumao + + + org.springframework.boot + spring-boot-starter-parent + 1.5.11.RELEASE + + + + 1.8 + 0.6.0 + 2.7.0 + 3.0.0 + UTF-8 + UTF-8 + + + + + + + io.springfox + springfox-swagger2 + ${springfox.version} + + + io.springfox + springfox-swagger-ui + ${springfox.version} + + + + + org.springframework.boot + spring-boot-starter-aop + + + + + com.fasterxml.jackson.core + jackson-core + 2.8.7 + + + com.fasterxml.jackson.core + jackson-annotations + 2.6.7 + + + com.fasterxml.jackson.core + jackson-databind + 2.6.7 + + + + + + + + + + nexus-aliyun + Nexus aliyun + http://maven.aliyun.com/nexus/content/groups/public + + true + + + false + + + + + + + nexus-aliyun + Nexus aliyun + http://maven.aliyun.com/nexus/content/groups/public + + true + + + false + + + + + +