From 2dc8fd2882de111c08e4dcd0c125235b6619573e Mon Sep 17 00:00:00 2001 From: Yeser Date: Mon, 27 Apr 2026 15:53:53 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84nacos=20+=20gateway=20+=20jdk?= =?UTF-8?q?17=20+=E4=BF=AE=E5=A4=8D=20=E6=94=AF=E4=BB=98=E5=B9=82=E7=AD=89?= =?UTF-8?q?=E5=92=8C=E8=AE=A2=E5=8D=95=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/fix_log_20260427.md | 69 + docs/interview_final.md | 231 ++++ docs/interview_qa.md | 699 ++++++++++ docs/interview_scenario_qa.md | 250 ++++ docs/upgrade_log_phase1.md | 1139 +++++++++++++++++ siam-common/pom.xml | 63 +- .../package_common/config/Swagger2Config.java | 62 +- .../mod_websocket/WebSocketBaseServer.java | 12 +- .../pojo/login/SysLoginAdmin.java | 24 +- .../pojo/login/SysLoginMerchant.java | 32 +- .../pojo/login/SysLoginRider.java | 32 +- .../MsgSendConfirmCallback.java | 8 +- .../MsgSendReturnsCallback.java | 16 +- .../rabbitmq_config/RabbitMqConfig.java | 2 +- .../package_common/service/AliyunSms.java | 2 +- .../package_common/service/EmailService.java | 4 +- .../siam/package_common/util/CommonUtils.java | 2 +- .../siam/package_common/util/CookieUtils.java | 2 +- .../util/ImageComposeUtils.java | 107 +- .../siam/package_common/util/PrintUtils.java | 2 +- .../siam/package_common/util/StringUtils.java | 2 +- siam-eureka/pom.xml | 11 +- siam-gateway/pom.xml | 77 ++ .../package_gateway/GatewayApplication.java | 14 + .../filter/AuthGlobalFilter.java | 95 ++ .../filter/RequestLogGlobalFilter.java | 52 + .../filter/ResponseLogGlobalFilter.java | 68 + .../src/main/resources/application.yml | 108 ++ siam-generator/kitty-common/pom.xml | 6 +- siam-generator/kitty-core/pom.xml | 14 +- siam-generator/kitty-dbms/pom.xml | 20 +- siam-generator/kitty-generator-pom/pom.xml | 8 +- siam-generator/kitty-generator/pom.xml | 43 +- .../kitty/generator/config/SwaggerConfig.java | 29 +- .../controller/GenerateController.java | 2 +- siam-generator/pom.xml | 4 +- siam-goods/goods-api/pom.xml | 4 - .../com/siam/package_goods/entity/Goods.java | 57 +- .../entity/GoodsAccessories.java | 19 +- .../entity/GoodsRawmaterialRelation.java | 15 +- .../entity/GoodsSpecification.java | 15 +- .../entity/GoodsSpecificationOption.java | 21 +- .../com/siam/package_goods/entity/Menu.java | 17 +- .../entity/MenuGoodsRelation.java | 13 +- .../package_goods/entity/Rawmaterial.java | 25 +- .../package_goods/entity/ShoppingCart.java | 21 +- .../entity/internal/MemberGoodsCollect.java | 19 +- .../package_goods/feign/GoodsFeignApi.java | 12 + .../package_goods/model/dto/GoodsMenuDto.java | 12 +- .../model/dto/GoodsSpecificationDto.java | 14 +- .../model/dto/GoodsSpecificationDto11.java | 6 +- .../dto/GoodsSpecificationOptionDto.java | 8 +- .../dto/internal/MemberGoodsCollectDto.java | 4 +- .../package_goods/model/param/GoodsParam.java | 2 +- .../model/param/SearchParam.java | 2 +- siam-goods/goods-provider/pom.xml | 37 +- .../siam/package_goods/GoodsApplication.java | 12 +- .../config/MybatisPlusConfig.java | 11 +- .../package_goods/config/Swagger2Config.java | 35 - .../AdminGoodsAccessoriesController.java | 15 +- .../admin/AdminGoodsController.java | 95 +- ...minGoodsRawmaterialRelationController.java | 19 +- .../AdminGoodsSpecificationController.java | 27 +- ...minGoodsSpecificationOptionController.java | 23 +- .../controller/admin/AdminMenuController.java | 15 +- .../admin/AdminRawmaterialController.java | 15 +- .../admin/AdminShoppingCartController.java | 15 +- .../admin/AdminStatisticsController.java | 5 +- .../AdminPointsMallStatisticsController.java | 5 +- .../controller/member/GoodsController.java | 53 +- .../member/GoodsSpecificationController.java | 5 +- .../GoodsSpecificationOptionController.java | 15 +- .../member/MRecommendGoodsController.java | 5 +- .../controller/member/MenuController.java | 5 +- .../member/ShoppingCartController.java | 7 +- .../MemberGoodsCollectController.java | 7 +- .../MerchantGoodsAccessoriesController.java | 54 +- .../merchant/MerchantGoodsController.java | 156 +-- ...antGoodsRawmaterialRelationController.java | 68 +- .../MerchantGoodsSpecificationController.java | 44 +- ...antGoodsSpecificationOptionController.java | 65 +- .../merchant/MerchantMenuController.java | 46 +- .../MerchantRawmaterialController.java | 55 +- .../MerchantRecommendGoodsController.java | 13 +- .../MerchantStatisticsController.java | 5 +- .../feign/GoodsFeignProvider.java | 11 + .../package_goods/mapper/GoodsMapper.java | 13 + .../service_impl/GoodsServiceImpl.java | 18 +- .../service_impl/StatisticsServiceImpl.java | 129 +- .../PointsMallStatisticsServiceImpl.java | 123 +- .../src/main/resources/application-local.yml | 51 +- siam-goods/pom.xml | 2 - siam-mall/mall-api/pom.xml | 3 - .../package_mall/entity/PointsMallGoods.java | 49 +- .../entity/PointsMallGoodsSpecification.java | 15 +- .../PointsMallGoodsSpecificationOption.java | 21 +- .../entity/PointsMallMemberGoodsCollect.java | 17 +- .../package_mall/entity/PointsMallMenu.java | 3 +- .../entity/PointsMallMenuGoodsRelation.java | 13 +- .../package_mall/entity/PointsMallOrder.java | 3 +- .../entity/PointsMallOrderDetail.java | 23 +- .../entity/PointsMallShoppingCart.java | 19 +- .../model/dto/PointsMallGoodsMenuDto.java | 12 +- .../dto/PointsMallGoodsSpecificationDto.java | 14 +- .../PointsMallGoodsSpecificationDto11.java | 6 +- ...PointsMallGoodsSpecificationOptionDto.java | 8 +- .../dto/PointsMallMemberGoodsCollectDto.java | 4 +- .../model/param/PointsMallOrderParam.java | 13 +- .../package_mall/model/param/SearchParam.java | 2 +- .../model/result/PointsMallOrderResult.java | 4 +- .../model/vo/PointsMallOrderVo.java | 4 +- siam-mall/mall-provider/pom.xml | 57 +- .../siam/package_mall/MallApplication.java | 16 +- .../config/MybatisPlusConfig.java | 11 +- .../package_mall/config/Swagger2Config.java | 35 - .../AdminPointsMallCouponsController.java | 19 +- ...ntsMallCouponsGoodsRelationController.java | 11 +- ...tsMallCouponsMemberRelationController.java | 11 +- ...PointsMallFullReductionRuleController.java | 17 +- .../admin/AdminPointsMallGoodsController.java | 77 +- ...ointsMallGoodsSpecificationController.java | 27 +- ...allGoodsSpecificationOptionController.java | 23 +- .../admin/AdminPointsMallMenuController.java | 17 +- .../admin/AdminPointsMallOrderController.java | 70 +- .../AdminPointsMallOrderDetailController.java | 71 +- ...minPointsMallOrderLogisticsController.java | 9 +- ...AdminPointsMallShoppingCartController.java | 15 +- ...tsMallCouponsMemberRelationController.java | 55 +- ...PointsMallFullReductionRuleController.java | 34 +- .../member/PointsMallGoodsController.java | 54 +- ...ointsMallGoodsSpecificationController.java | 5 +- ...allGoodsSpecificationOptionController.java | 22 +- ...ointsMallMemberGoodsCollectController.java | 7 +- .../member/PointsMallMenuController.java | 5 +- .../member/PointsMallOrderController.java | 13 +- .../PointsMallOrderDetailController.java | 26 +- .../PointsMallOrderLogisticsController.java | 9 +- .../PointsMallPlatformPayController.java | 13 +- .../PointsMallShoppingCartController.java | 7 +- .../member/PointsMallWxPayService.java | 4 +- .../feign/PointsMallOrderFeignProvider.java | 2 +- .../mqConsumer/PointsMallGoodsConsumer.java | 2 +- .../mqConsumer/PointsMallOrderConsumer.java | 2 +- .../PointsMallOrderLogisticsServiceImpl.java | 4 +- .../PointsMallOrderServiceImpl.java | 3 + .../src/main/resources/application-local.yml | 59 +- siam-mall/pom.xml | 2 - siam-merchant/merchant-api/pom.xml | 3 - .../package_merchant/entity/Merchant.java | 35 +- .../siam/package_merchant/entity/Shop.java | 4 +- .../param/MerchantWithdrawRecordParam.java | 2 +- .../model/param/ShopChangeRecordParam.java | 2 +- .../model/param/ShopParam.java | 4 +- .../package_merchant/util/HttpContext.java | 4 +- .../siam/package_merchant/util/TokenUtil.java | 6 +- siam-merchant/merchant-provider/pom.xml | 36 +- .../package_merchant/MerchantApplication.java | 11 +- .../config/MybatisPlusConfig.java | 11 +- .../config/Swagger2Config.java | 35 - .../AdminMerchantBillingRecordController.java | 11 +- .../admin/AdminMerchantController.java | 5 +- ...AdminMerchantWithdrawRecordController.java | 11 +- .../AdminShopChangeRecordController.java | 11 +- .../controller/admin/AdminShopController.java | 17 +- .../controller/member/ShopController.java | 5 +- .../controller/member/WxLoginController.java | 5 +- .../MerchantBillingRecordController.java | 11 +- .../merchant/MerchantController.java | 5 +- .../MerchantShopChangeRecordController.java | 46 +- .../merchant/MerchantShopController.java | 84 +- .../MerchantWithdrawRecordController.java | 35 +- .../src/main/resources/application-local.yml | 51 +- siam-merchant/pom.xml | 2 - siam-monitor/pom.xml | 20 +- .../java/com/siam/SecuritySecureConfig.java | 46 +- .../src/main/resources/application-local.yml | 18 +- siam-order/order-api/pom.xml | 3 - .../com/siam/package_order/entity/Order.java | 5 +- .../package_order/entity/OrderDetail.java | 23 +- .../model/dto/PlatformPayDto.java | 4 +- .../package_order/model/param/OrderParam.java | 9 +- .../siam/package_order/model/vo/OrderVo.java | 4 +- .../siam/package_order/model/vo/OrderVo2.java | 4 +- siam-order/order-provider/pom.xml | 57 +- .../siam/package_order/OrderApplication.java | 16 +- .../config/MybatisPlusConfig.java | 11 +- .../package_order/config/SeataConfig.java | 4 +- .../package_order/config/Swagger2Config.java | 35 - .../admin/AdminOrderController.java | 27 +- .../admin/AdminOrderDetailController.java | 71 +- .../controller/member/AppraiseController.java | 4 +- .../controller/member/CommonController.java | 24 +- .../controller/member/GiveLikeController.java | 2 +- .../member/MerchantOrderController.java | 114 +- .../member/MerchantOrderDetailController.java | 74 +- .../controller/member/OrderController.java | 41 +- .../member/OrderDetailController.java | 26 +- .../controller/member/PayDemoController.java | 62 +- .../member/PlatformPayController.java | 13 +- .../controller/member/ReplyController.java | 2 +- .../controller/member/WxPayService.java | 2 +- .../internal/WxNotifyTemplateController.java | 7 +- .../member/internal/WxPayController.java | 186 +-- .../DR_OrderController.java | 7 +- .../merchant/MerchantAppraiseController.java | 2 +- .../merchant/MerchantReplyController.java | 2 +- .../feign/OrderFeignProvider.java | 2 +- .../model/dto/OrderPaySuccessMessage.java | 19 + .../mq_consumer/OrderConsumer.java | 2 +- .../internal/OrderTransactionListener.java | 61 +- .../internal/TransactionProducer.java | 4 +- .../package_order/service/CommonService.java | 5 - .../package_order/service/OrderService.java | 2 - .../service_impl/CommonServiceImpl.java | 5 - .../service_impl/OrderServiceImpl.java | 132 +- .../internal/RewardServiceImpl.java | 14 +- .../LocalMsg_OrderServiceImpl.java | 616 --------- .../RocketMQ_OrderServiceImpl.java | 689 ---------- .../Seata_OrderServiceImpl.java | 692 ---------- .../src/main/resources/application-local.yml | 59 +- .../package_order/OrderApplicationTest.java | 2 +- .../internal/DistributedTransactionTest.java | 2 +- siam-order/pom.xml | 2 - siam-parent/pom.xml | 113 +- siam-promotion/pom.xml | 2 - siam-promotion/promotion-api/pom.xml | 4 - .../entity/Advertisement.java | 21 +- .../package_promotion/entity/Rawmaterial.java | 25 +- .../model/param/AdvertisementParam.java | 4 +- .../model/param/SearchParam.java | 2 +- siam-promotion/promotion-provider/pom.xml | 36 +- .../PromotionApplication.java | 12 +- .../config/MybatisPlusConfig.java | 11 +- .../config/Swagger2Config.java | 35 - .../admin/AdminAdvertisementController.java | 17 +- .../admin/AdminCouponsController.java | 19 +- .../AdminCouponsGoodsRelationController.java | 11 +- .../AdminCouponsMemberRelationController.java | 11 +- .../AdminCouponsShopRelationController.java | 11 +- .../admin/AdminPaperworkPushController.java | 17 +- .../member/AdvertisementController.java | 9 +- .../CouponsMemberRelationController.java | 44 +- .../member/FullReductionRuleController.java | 34 +- .../member/MemberAdvertisementController.java | 32 +- .../MerchantAdvertisementController.java | 59 +- .../merchant/MerchantCouponsController.java | 99 +- ...erchantCouponsGoodsRelationController.java | 35 +- ...rchantCouponsMemberRelationController.java | 29 +- .../MerchantFullReductionRuleController.java | 55 +- .../src/main/resources/application-local.yml | 51 +- .../package_promotion/ImageComposeTest.java | 194 +-- siam-rider/pom.xml | 2 - siam-rider/rider-api/pom.xml | 3 - .../com/siam/package_rider/entity/Rider.java | 6 +- .../siam/package_rider/util/HttpContext.java | 4 +- .../siam/package_rider/util/TokenUtil.java | 6 +- siam-rider/rider-provider/pom.xml | 36 +- .../siam/package_rider/RiderApplication.java | 11 +- .../config/MybatisPlusConfig.java | 11 +- .../package_rider/config/Swagger2Config.java | 35 - .../admin/AdminRiderController.java | 40 +- .../controller/member/WxLoginController.java | 5 +- .../merchant/MerchantRiderController.java | 53 +- .../src/main/resources/application-local.yml | 51 +- siam-user/pom.xml | 2 - siam-user/user-api/pom.xml | 3 - .../com/siam/package_user/entity/Admin.java | 27 +- .../siam/package_user/entity/AdminToken.java | 17 +- .../package_user/entity/DeliveryAddress.java | 3 +- .../siam/package_user/entity/MemberToken.java | 17 +- .../entity/MemberTradeRecord.java | 27 +- .../entity/internal/VipRechargeRecord.java | 5 +- .../jwt/AuthenticationInterceptor.java | 4 +- .../param/MemberWithdrawRecordParam.java | 2 +- .../siam/package_user/util/HttpContext.java | 4 +- .../com/siam/package_user/util/TokenUtil.java | 6 +- siam-user/user-provider/pom.xml | 36 +- .../siam/package_user/UserApplication.java | 12 +- .../config/MybatisPlusConfig.java | 23 +- .../package_user/config/Swagger2Config.java | 35 - .../controller/admin/AdminController.java | 5 +- .../admin/AdminDeliveryAddressController.java | 15 +- .../AdminMemberBillingRecordController.java | 50 +- .../admin/AdminMemberController.java | 35 +- .../AdminMemberTradeRecordController.java | 73 +- .../AdminMemberWithdrawRecordController.java | 11 +- ...dminVipRechargeDenominationController.java | 15 +- ...DenominationCouponsRelationController.java | 11 +- .../AdminVipRechargeRecordController.java | 19 +- .../member/DeliveryAddressController.java | 84 +- .../controller/member/MemberController.java | 5 +- .../MemberInviteRelationController.java | 18 +- .../member/MemberTradeRecordController.java | 22 +- .../MemberWithdrawRecordController.java | 11 +- .../controller/member/WxLoginController.java | 5 +- .../VipRechargeDenominationController.java | 9 +- .../internal/VipRechargeRecordController.java | 13 +- .../MemberBillingRecordServiceImpl.java | 2 + .../MemberInviteRelationServiceImpl.java | 2 + .../service_impl/MemberServiceImpl.java | 3 + .../src/main/resources/application-local.yml | 51 +- siam-util/pom.xml | 2 - siam-util/util-api/pom.xml | 3 - .../package_util/entity/ScheduledTask.java | 17 +- .../package_util/entity/ScheduledTaskLog.java | 17 +- .../com/siam/package_util/entity/Setting.java | 3 +- .../com/siam/package_util/entity/SmsLog.java | 21 +- .../siam/package_util/entity/SysMessage.java | 1 - .../model/param/PictureUploadRecordParam.java | 2 +- .../package_util/model/param/SearchParam.java | 2 +- siam-util/util-provider/pom.xml | 36 +- .../siam/package_util/UtilApplication.java | 11 +- .../config/MybatisPlusConfig.java | 11 +- .../package_util/config/Swagger2Config.java | 35 - .../AdminPictureUploadRecordController.java | 38 +- .../admin/AdminSettingController.java | 13 +- .../admin/AdminUploadController.java | 5 +- .../controller/member/SettingController.java | 26 +- .../controller/member/SmsLogController.java | 23 +- .../member/SystemUsageRecordController.java | 11 +- .../controller/member/UploadController.java | 11 +- ...MerchantPictureUploadRecordController.java | 30 +- .../merchant/MerchantSettingController.java | 20 +- .../merchant/MerchantUploadController.java | 11 +- .../internal/MerchantPrinterController.java | 56 +- .../PreviousWxNotifyServiceImpl.java | 18 +- .../src/main/resources/application-local.yml | 51 +- siam-weixin/pom.xml | 2 - siam-weixin/weixin-basic/pom.xml | 2 - .../package_weixin_basic/util/IpUtils.java | 2 +- siam-weixin/weixin-pay/pom.xml | 2 - .../config/WxpayConfigDemo.java | 2 +- .../package_weixin_pay/entity/WxPayDto.java | 4 +- .../entity/WxpayConfig.java | 2 +- .../siam/package_weixin_pay/util/PayUtil.java | 2 +- siam-zuul/Dockerfile | 19 - siam-zuul/jmx_exporter.yml | 10 - siam-zuul/jmx_prometheus_javaagent-0.15.0.jar | Bin 418240 -> 0 bytes siam-zuul/pom.xml | 118 -- .../siam/package_zuul/ZuulApplication.java | 73 -- .../package_zuul/config/ActuatorConfig.java | 16 - .../package_zuul/config/Swagger2Config.java | 35 - .../package_zuul/config/WebMvcConfig.java | 95 -- .../siam/package_zuul/filter/AdminFilter.java | 130 -- .../BodyReaderHttpServletRequestWrapper.java | 79 -- .../siam/package_zuul/filter/Constant.java | 13 - .../package_zuul/filter/EncryptFilter.java | 162 --- .../package_zuul/filter/MemberFilter.java | 131 -- .../package_zuul/filter/MerchantFilter.java | 123 -- .../package_zuul/filter/RateLimitFilter.java | 105 -- .../filter/RateLimitFilter01.java | 55 - .../filter/RateLimitFilter02.java | 98 -- .../package_zuul/filter/RequestLogFilter.java | 140 -- .../filter/ResponseLogFilter.java | 104 -- .../src/main/resources/application-local.yml | 155 --- siam-zuul/src/main/resources/application.yml | 5 - siam-zuul/src/main/resources/banner.txt | 7 - .../src/main/resources/logback-spring.xml | 116 -- sql/mysql/siam_cloud.sql | 1 + vue-siam-admin/config/index.js | 12 +- vue-siam-admin/package-lock.json | 60 +- .../src/pages/shopManage/shopList.vue | 4 +- 362 files changed, 5670 insertions(+), 8233 deletions(-) create mode 100644 docs/fix_log_20260427.md create mode 100644 docs/interview_final.md create mode 100644 docs/interview_qa.md create mode 100644 docs/interview_scenario_qa.md create mode 100644 docs/upgrade_log_phase1.md create mode 100644 siam-gateway/pom.xml create mode 100644 siam-gateway/src/main/java/com/siam/package_gateway/GatewayApplication.java create mode 100644 siam-gateway/src/main/java/com/siam/package_gateway/filter/AuthGlobalFilter.java create mode 100644 siam-gateway/src/main/java/com/siam/package_gateway/filter/RequestLogGlobalFilter.java create mode 100644 siam-gateway/src/main/java/com/siam/package_gateway/filter/ResponseLogGlobalFilter.java create mode 100644 siam-gateway/src/main/resources/application.yml delete mode 100644 siam-goods/goods-provider/src/main/java/com/siam/package_goods/config/Swagger2Config.java delete mode 100644 siam-mall/mall-provider/src/main/java/com/siam/package_mall/config/Swagger2Config.java delete mode 100644 siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/config/Swagger2Config.java delete mode 100644 siam-order/order-provider/src/main/java/com/siam/package_order/config/Swagger2Config.java create mode 100644 siam-order/order-provider/src/main/java/com/siam/package_order/model/dto/OrderPaySuccessMessage.java delete mode 100644 siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/internal/distributed_transaction/LocalMsg_OrderServiceImpl.java delete mode 100644 siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/internal/distributed_transaction/RocketMQ_OrderServiceImpl.java delete mode 100644 siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/internal/distributed_transaction/Seata_OrderServiceImpl.java delete mode 100644 siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/config/Swagger2Config.java delete mode 100644 siam-rider/rider-provider/src/main/java/com/siam/package_rider/config/Swagger2Config.java delete mode 100644 siam-user/user-provider/src/main/java/com/siam/package_user/config/Swagger2Config.java delete mode 100644 siam-util/util-provider/src/main/java/com/siam/package_util/config/Swagger2Config.java delete mode 100644 siam-zuul/Dockerfile delete mode 100644 siam-zuul/jmx_exporter.yml delete mode 100644 siam-zuul/jmx_prometheus_javaagent-0.15.0.jar delete mode 100644 siam-zuul/pom.xml delete mode 100644 siam-zuul/src/main/java/com/siam/package_zuul/ZuulApplication.java delete mode 100644 siam-zuul/src/main/java/com/siam/package_zuul/config/ActuatorConfig.java delete mode 100644 siam-zuul/src/main/java/com/siam/package_zuul/config/Swagger2Config.java delete mode 100644 siam-zuul/src/main/java/com/siam/package_zuul/config/WebMvcConfig.java delete mode 100644 siam-zuul/src/main/java/com/siam/package_zuul/filter/AdminFilter.java delete mode 100644 siam-zuul/src/main/java/com/siam/package_zuul/filter/BodyReaderHttpServletRequestWrapper.java delete mode 100644 siam-zuul/src/main/java/com/siam/package_zuul/filter/Constant.java delete mode 100644 siam-zuul/src/main/java/com/siam/package_zuul/filter/EncryptFilter.java delete mode 100644 siam-zuul/src/main/java/com/siam/package_zuul/filter/MemberFilter.java delete mode 100644 siam-zuul/src/main/java/com/siam/package_zuul/filter/MerchantFilter.java delete mode 100644 siam-zuul/src/main/java/com/siam/package_zuul/filter/RateLimitFilter.java delete mode 100644 siam-zuul/src/main/java/com/siam/package_zuul/filter/RateLimitFilter01.java delete mode 100644 siam-zuul/src/main/java/com/siam/package_zuul/filter/RateLimitFilter02.java delete mode 100644 siam-zuul/src/main/java/com/siam/package_zuul/filter/RequestLogFilter.java delete mode 100644 siam-zuul/src/main/java/com/siam/package_zuul/filter/ResponseLogFilter.java delete mode 100644 siam-zuul/src/main/resources/application-local.yml delete mode 100644 siam-zuul/src/main/resources/application.yml delete mode 100644 siam-zuul/src/main/resources/banner.txt delete mode 100644 siam-zuul/src/main/resources/logback-spring.xml diff --git a/docs/fix_log_20260427.md b/docs/fix_log_20260427.md new file mode 100644 index 0000000..d48f92a --- /dev/null +++ b/docs/fix_log_20260427.md @@ -0,0 +1,69 @@ +# Siam-Cloud 修复日志 + +## 修复时间 + +2026-04-27 + +--- + +## 修复一:退款回调逻辑错误(P0) + +### 问题描述 + +`WxPayController.refundSuccessNotify()` 存在两个 Bug: + +1. **状态检查错误**:使用 `!= INT_1`(待支付)判断交易状态。退款回调发生时交易记录已被 `wxNotify` 更新为 `INT_2`(已支付),导致判断恒为 true,退款回调永远被跳过。 +2. **业务逻辑错误**:try 块中调用了 `orderService.paymentNotify()`(支付成功通知、打印小票、语音提醒),而非退款处理逻辑。 + +深层问题:系统在 admin 审批退款时通过 `refundBase()` 同步执行全部退款流程,未等待微信退款 API 的异步回调确认。若微信端退款失败,本地已产生不可逆的资金操作。 + +### 修复内容 + +**文件**:`siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/internal/WxPayController.java` + +| 改动点 | 修复前 | 修复后 | +|--------|--------|--------| +| 状态检查 | `dbMemberTradeRecord.getStatus() != Quantity.INT_1` | `dbMemberTradeRecord.getStatus() != Quantity.INT_2` | +| 业务处理 | `orderService.paymentNotify(outTradeNo)` | `orderService.refundMerchantBalance(outTradeNo)` | +| 无用代码 | 再次将交易记录设为 INT_2(原已是 INT_2) | 已移除 | +| 状态异常响应 | 仅打印日志后静默 return,微信会持续重试 | 返回 SUCCESS XML,终止微信重试 | + +--- + +## 修复二:Seata 分布式事务激活(P1) + +### 问题描述 + +1. `Seata_OrderServiceImpl` 是一个空壳类,所有方法返回 null/0/false,`@GlobalTransactional` 被注释 +2. `OrderServiceImpl.insert()`(实际使用的实现)无 `@GlobalTransactional` +3. Seata 依赖未在任何 pom.xml 中声明,8 个 provider 的 Seata 配置为孤立配置 +4. 跨服务下单(订单创建 + 删购物车 + 核销优惠券 + 更新会员)无分布式事务保障 + +### 修复内容 + +| 改动 | 文件 | +|------|------| +| 新增 `spring-cloud-starter-alibaba-seata` 依赖 | `siam-common/pom.xml` | +| 添加 `@GlobalTransactional(timeoutMills = 300000, name = "order-create")` | `OrderServiceImpl.insert()` | +| 添加 import `io.seata.spring.annotation.GlobalTransactional` | `OrderServiceImpl.java` | +| 删除空壳类 | `Seata_OrderServiceImpl.java` | + +**注意**:激活后需启动 Seata Server 才能正常下单。 + +--- + +## 附加发现(未修复) + +| 问题 | 位置 | 说明 | +|------|------|------| +| RocketMQ 延时关单被注释 | `OrderServiceImpl.java:279` | 超时未支付订单不会自动关闭 | +| `RocketMQ_OrderServiceImpl` | `distributed_transaction/` | 同为待确认状态的实现类 | +| `LocalMsg_OrderServiceImpl` | `distributed_transaction/` | 同上 | + +--- + +## 修复后待验证 + +- [ ] 编译通过(`mvn compile`) +- [ ] 退款流程端到端验证 +- [ ] Seata Server 启动后下单链路验证 diff --git a/docs/interview_final.md b/docs/interview_final.md new file mode 100644 index 0000000..74b10be --- /dev/null +++ b/docs/interview_final.md @@ -0,0 +1,231 @@ +# Siam-Cloud 架构师面试实战手册(最终纯净版) + +> 人设定位:Siam-Cloud 微服务核心架构师 / 高级后端开发 +> 项目背景:基于原生 Spring Boot 3.2 + Spring Cloud Alibaba (Nacos, Seata, Sentinel) + Gateway + RocketMQ + ShardingSphere + Redis 打造的高并发外卖/商城平台 + +--- + +## 维度一:API 网关与流量治理 (Gateway + Sentinel) + +### Q1:你们项目拆分了 10 个微服务,前端请求的鉴权和跨域是怎么统一管理的? + +**【情境】:** 在分布式微服务架构下,如果让订单、用户、商品等每个独立服务都去处理 Token 解析和 CORS(跨域),会导致代码严重冗余,且鉴权标准极易出现漏洞。 + +**【任务】:** 设计一个统一的流量入口,将安全校验、跨域等非业务逻辑彻底下沉到基础设施层。 + +**【行动】:** +1. 我基于 Spring Cloud Gateway 的 WebFlux 响应式模型构建了统一网关。 +2. **跨域控制**:在 Gateway 层面配置 `globalcors`,彻底剥离后端 Provider 的跨域关注点,实现全站统一跨域策略。 +3. **全局鉴权**:设计了自定义 `AuthGlobalFilter`。在网关层拦截所有外部请求,校验 Token 的合法性。校验通过后,将 Token 写入 `X-Auth-Token` 请求头中透传给下游服务。对于 `/login`、`/notify`、`/callback` 等接口开放白名单放行。 +4. **路由改写**:利用 `StripPrefix=1` 过滤器精准剥离外部访问的前缀(如将 `/api-order/rest/xxx` 剥离为 `/rest/xxx`),实现内外网路径的物理隔离与映射。 + +**【结果】:** 实现了内部微服务的"无状态化"与"零鉴权负担",下游服务只需从请求头获取用户信息即可,大幅提升了系统的安全性与横向扩展能力。 + +--- + +### Q2:如果遇到大促或者外卖高峰期,网关层如何保护后端微服务不被流量洪峰打垮? + +**【情境】:** 午餐高峰期,并发订单请求可能瞬间飙升,如果直接打到订单或商品服务,容易引起数据库连接池耗尽,进而导致全链路雪崩。 + +**【任务】:** 在网关层建立第一道防线,实现灵活的限流与熔断降级。 + +**【行动】:** +1. 引入 Sentinel 结合 Gateway 进行入口级别的全局流量控制。 +2. 针对核心下单 API 设置基于 QPS 的限流规则(采用令牌桶算法),当请求超过系统承载阈值时,触发快速失败机制。 +3. 配置定制化的 `BlockRequestHandler`。在触发限流时,不返回生硬的 500/503 报错,而是返回友好的 JSON 业务提示(如"当前抢单人数过多,请稍后再试")。 +4. Gateway 本身基于 WebFlux 响应式异步模型,相比传统阻塞模型,同等硬件资源下可承载更高的并发连接数。 + +**【结果】:** 在大流量压测下,系统不仅能够有效削峰填谷,还能保证核心链路(如支付、下单)的资源倾斜,做到了真正的高可用。 + +--- + +## 维度二:高并发支付与资金安全 (Redis 核心场景) + +### Q3:外卖系统的支付回调极其关键。如果微信/支付宝服务器因为网络抖动发起了高并发的重复回调,你们如何保证资金安全? + +**【情境】:** 第三方支付平台(如微信)在未收到我方明确的 HTTP 200 响应时,会以指数级时间(15s, 30s, 3m...)进行疯狂的重复回调通知。如果不加干预,会导致一笔订单被重复加钱、重复发货。 + +**【任务】:** 实现绝对的支付回调幂等性控制,且防范外部恶意请求伪造。 + +**【行动】:** 我利用 Redis 分布式锁设计了防御纵深: + +1. **验签前置**:在进入任何业务逻辑前,先调用我底层封装的数字签名校验工具类,严格遵循微信支付 V2 的 MD5 签名规范——将所有参数按字典序排序拼接,末尾拼接 `&key=` + 商户密钥,生成签名后与回调中的 `sign` 字段逐字比对,拦截恶意伪造的虚假支付请求。 +2. **SETNX 锁控制**:以 `pay:callback:lock:{订单号}` 作为 Key,执行带有过期时间(设定为 3 分钟,防止服务宕机导致死锁)的 `setIfAbsent` 操作。 +3. **拦截与确认**:如果加锁失败,说明该订单的回调正在被处理,系统直接向微信返回 `SUCCESS`,主动切断微信的后续重试机制。 +4. **核心策略(亮点)**:在 `finally` 块中,我故意不主动释放锁,而是让其保留至自然过期。这就完美抵御了微信在极短时间内的并发重发击穿。 + +**【结果】:** 彻底消除了重复支付回调造成的资金风险,上线至今保证了账务数据的绝对最终一致。 + +--- + +### Q4:除了支付回调,Redis 在你们项目中还承载了哪些核心场景? + +**【情境】:** 一个成熟的微服务系统,Redis 不能只做简单的 KV 缓存,需要承担更多核心职责。 + +**【任务】:** 梳理项目中 Redis 的关键应用场景,确保每个场景的选型和实现都经得起生产环境的考验。 + +**【行动】:** + +| 场景 | 数据结构 | 设计要点 | +|------|---------|---------| +| **用户 Session** | String(Key: `LOGIN_USER:{token}`) | 登录成功写入,设置 7 天 TTL;活跃用户持续续期 | +| **支付幂等锁** | String(Key: `pay:callback:lock:{outTradeNo}`) | SETNX 实现,3 分钟过期,不主动删锁 | +| **短信验证码** | String(Key: `sms:code:{mobile}`) | 5 分钟过期,发送时覆盖旧值 | +| **购物车缓存** | Hash(Key: `cart:{userId}`) | 用户加购时先写 Redis,下单时同步到 DB | +| **登录重试限制** | String(Key: `login:lock:{ip}`) | 连续输错密码 5 次后锁定 15 分钟 | + +**设计原则:** +1. 所有 Key 统一前缀,便于运维排查和管理 +2. 过期时间必须有,防止内存泄漏 +3. 大 Key 预警:购物车超过 100 个商品时异步刷盘 +4. 容灾降级:Redis 不可用时,Session 查询降级为查 DB + +**【结果】:** Redis 在项目中承担了认证、幂等、缓存、限流等多重职责,每个场景根据业务特性选择了合适的数据结构,配合 TTL、前缀规范、容灾降级策略,确保在生产环境下稳定运行。 + +--- + +## 维度三:分布式事务与异步流转 (Seata + RocketMQ) + +### Q5:用户下单时,需要同时调用订单服务创单、商品服务扣库存、促销服务核销优惠券。如果中途报错,怎么保证数据的一致性? + +**【情境】:** 在微服务架构下,本地的 `@Transactional` 只能管辖单一数据库。跨微服务的 RPC 调用一旦出现网络超时或下游报错,极易产生部分成功、部分失败的"脏数据"(如库存扣了但订单没生成)。 + +**【任务】:** 在保证系统吞吐量的前提下,实现跨微服务下单链路的强一致性。 + +**【行动】:** 我主导引入了 Seata 的 AT(Automatic Transaction)模式: + +1. 以外部网关的下单请求为起点,在 Order 服务的发起端打上 `@GlobalTransactional` 注解,向 TC(事务协调器)注册全局事务 XID。 +2. Seata 会在底层自动拦截各个服务的业务 SQL,在执行业务操作前,生成包含修改前和修改后数据的 `undo_log`(回滚日志),并与业务数据在同一个本地事务中提交。 +3. 如果调用链上的任何一个节点抛出异常,TC 会立即向所有参与者下发回滚指令,各节点利用 `undo_log` 中的前置镜像生成反向 SQL 进行自动补偿。 +4. **一致性级别权衡**:资金相关和核心业务(余额扣减、库存扣减、订单创建)走强一致性(Seata);非核心链路(通知、日志、统计)走最终一致性(RocketMQ)。 + +**【结果】:** 以极小的代码侵入性(仅加注解),完美保障了核心下单链路的强一致性,有效防止了外卖平台的超卖事故。 + +--- + +### Q6:下单支付成功后,系统还要发短信、给骑手派单、更新报表。如果这些都写在主流程里,响应太慢怎么办? + +**【情境】:** 支付成功后的后置动作繁多,导致核心接口响应时间长(RT),且一旦边缘接口(如发短信)挂了,会导致整个主流程报错回滚,系统耦合度极高。 + +**【任务】:** 对核心链路进行深度解耦,提升吞吐量与容错率。 + +**【行动】:** 采用 RocketMQ 事务消息实现最终一致性: + +1. 支付服务在确认收款后,首先通过 RocketMQ 发送一条半消息(Half Message)到 Broker,此时消息对消费者不可见。 +2. 执行本地事务(修改订单状态为"已支付",记录支付流水)。 +3. 本地事务成功后,向 Broker 发送 Commit 指令,此时消息才真正投递给下游(短信、派单系统)进行异步消费。 +4. **容错机制**:万一支付服务在发送 Commit 前宕机,MQ 的回查机制会反向调用我实现的 `checkLocalTransaction` 接口,检查数据库订单状态,决定是 Commit 还是 Rollback。 + +**【结果】:** 核心支付接口的 RT 从 1.5 秒压降到了 200 毫秒以内,极大地提升了用户体验,并实现了各业务域的物理隔离。 + +--- + +## 维度四:海量数据路由与分片 (ShardingSphere) + +### Q7:随着系统订单量暴增,单表千万级数据导致查询极慢,你是如何设计数据库存储架构的? + +**【情境】:** 外卖系统的历史订单数据增长极快,MySQL 单库单表(tb_order)很快遇到了 B+ 树索引层级过深、I/O 遇到瓶颈的严重性能衰退问题。 + +**【任务】:** 在不改变上层 Java 业务代码(依然使用 MyBatis-Plus 标准写法)的前提下,实现数据库的水平无缝扩容。 + +**【行动】:** 我引入了 Apache ShardingSphere-JDBC 作为数据层的智能路由引擎: + +1. **分片键选择**:经过对慢 SQL 频次的分析,发现绝大部分高频查询是"C 端用户查自己的订单"。因此我选取 `member_id` 作为分库键,`order_id` 作为分表键。 +2. **路由算法设计**:采用标准 Inline 表达式。将数据库水平拆分为 `siam_cloud_0` 和 `siam_cloud_1`(路由逻辑:`member_id % 2`),单库内再分为 `tb_order_0` 和 `tb_order_1`(路由逻辑:`order_id % 2`)。 +3. **分布式主键**:弃用数据库自增 ID,全面接入雪花算法(Snowflake)生成趋势递增且全局唯一的订单 ID,防止数据合并时的主键冲突。 + +**【结果】:** 将单表 I/O 压力完美均摊到多个物理节点,系统轻松支撑亿级订单数据。上层微服务对底层的分表完全无感知,实现了架构的平滑扩容。 + +--- + +### Q8:分库分表后,分页查询和跨分片统计怎么解决? + +**【情境】:** 分库分表后,跨分片的分页查询性能很差,因为需要聚合所有分片的结果再排序。管理后台的订单列表和统计数据面临挑战。 + +**【任务】:** 在分片架构下保障管理端查询效率和数据准确性。 + +**【行动】:** +1. **分页查询优化**:管理后台的分页查询一般不跨分片——按商家维度查询(商家 id 固定),天然路由到单一分片。对于需要全局数据的场景,限制最大页数(如最多翻 100 页)。 +2. **统计数据预聚合**:对于大数据量统计(如今日交易额、订单数),通过定时任务预聚合到统计表中,查询时直接读统计表而非实时扫分片。 +3. **主键全局唯一**:使用雪花算法确保各分片的主键不冲突,便于后续可能的数据迁移和合并。 + +**【结果】:** 管理端查询响应时间控制在 200ms 以内,统计数据通过预聚合避免了实时跨分片扫描带来的性能开销。 + +--- + +## 维度五:服务治理与 RPC 通信 (Nacos + Feign) + +### Q9:为什么选用 Nacos 作为基础设施?在服务上下线时,如何避免流量打到已经挂掉的节点? + +**【情境】:** 微服务节点众多,需要健壮的注册中心和配置中心。同时,服务重启、发布、扩容时,如果负载均衡器仍将请求路由到已下线的实例,会导致大量请求失败。 + +**【任务】:** 构建稳固的服务发现机制,实现优雅上下线和零宕机发布。 + +**【行动】:** + +1. **基础设施选型**:选用 Nacos 2.x,因为它天然集成了 Discovery(注册)和 Config(配置),支持长轮询机制,比传统的 Eureka 具有更快的上下线感知速度。Nacos 同时支持 AP 和 CP 模式,我们默认使用 AP 模式保障服务发现的高可用。 + +2. **服务下线(优雅停机)**: + - 主动注销:服务关闭前主动向 Nacos 发起注销请求,标记自己为不健康状态 + - 被动检测:Nacos 心跳检测发现服务超过 15 秒无心跳,自动将其标记为不健康并剔除 + - LoadBalancer 缓存刷新:客户端缓存的服务实例列表有 TTL(默认 30 秒),超时后重新从 Nacos 拉取,自动剔除不健康实例 + +3. **服务上线(健康就绪)**: + - 延迟注册:服务启动时不立即注册,等待 Spring 容器初始化完成、数据库连接池就绪后再注册 + - 健康检查通过后才接收流量:Nacos 只将健康实例纳入负载均衡列表 + +4. **Gateway 层防护**:路由使用 `lb://service-name` 协议,当某个实例宕机被剔除后,Gateway 自动将后续请求路由到剩余健康实例。 + +**【结果】:** 通过主动注销 + 被动检测 + LoadBalancer 缓存刷新的三重机制,确保服务下线后流量在 30 秒内自动切换到健康实例,实现服务发布期间对用户无感知的平滑过渡。 + +--- + +### Q10:在 RPC 服务间调用(Feign)中,你做过哪些核心的容错设计? + +**【情境】:** 微服务间的 Feign 调用经常因为网络抖动、下游服务未启动、或者序列化问题引发各种异常。尤其是下游返回的包装类 `BasicResult` 中,`getData()` 可能为 null,如果业务层直接拆箱为 `int` 或 `BigDecimal`,会导致连环 `NullPointerException`。 + +**【任务】:** 彻底扫除 Feign 调用的隐藏地雷,增强 RPC 调用的鲁棒性。 + +**【行动】:** + +1. **Feign 拆箱安全防范(亮点)**:我们的 RPC 接口统一返回了带有泛型的 `BasicResult` 包装类。我发现在复杂网络下,如果下游服务未启动或发生熔断,返回的 `.getData()` 极易为 null。如果业务层直接拆箱,会导致连环 NullPointerException。为此,我在底层架构中统一封装了安全拆箱工具方法(`safeInt`、`safeBigDecimal`),拦截所有非法 null 值并赋予合理的业务默认值(如 0 或 `BigDecimal.ZERO`),全局覆盖了 60+ 处调用点。 + +2. **Token 隐式透传**:通过实现 `RequestInterceptor`,在 Feign 发起调用前,自动将上下文中的 `X-Auth-Token` 提取并注入到新的 Request Header 中,保证了用户登录态在微服务链路中的无缝穿透。 + +3. **超时配置**:为 Feign 配置了合理的连接超时(5 秒)和读取超时(10 秒),防止下游服务响应慢导致调用方线程池耗尽。 + +**【结果】:** 消除了至少 60 多处潜在的空指针隐患,极大增强了 RPC 调用的鲁棒性,系统的联调效率提升了 40%。 + +--- + +## 附录:高频面试话术 + +### 如何回答"你遇到过最难的问题是什么?" + +> "在做支付模块的时候,微信支付回调的验签和幂等控制是两个关键挑战。验签方面,微信支付 V2 使用 MD5 签名,要求将所有参数按字典序排序后拼接 `&key=` + 商户密钥来计算签名。这个环节对输入极其敏感,差一个字符结果就完全不同。我通过逐字比对微信官方文档的签名示例,确保了验签逻辑的精确性。幂等方面,微信在网络抖动时会重复发送同一笔订单的回调,我用 Redis SETNX 实现了分布式锁,以订单号为 Key,3 分钟过期,并且在 finally 中故意不主动释放锁,让其保留至自然过期,完美抵御了微信在极短时间内的并发重发击穿。这件事让我深刻认识到:**和外部系统对接时,必须严格按照官方文档的每一个细节实现,不能凭感觉'差不多就行'。**" + +### 如何回答"你们项目的技术亮点是什么?" + +> "我认为最大的亮点是**在高并发场景下的稳定性设计**。体现在三个层面:第一,网关层统一鉴权 + 限流,在请求入口就过滤掉无效和超限流量;第二,支付模块的双重安全防线——验签防伪造 + 分布式锁防重复,确保资金操作的绝对安全;第三,通过 Seata 和 RocketMQ 分别处理强一致性和最终一致性场景,让不同重要级别的数据采用不同的保障策略,而不是'一刀切'。这些设计都是在真实的生产压力下打磨出来的,不是纸上谈兵。" + +### 如何回答"你觉得这个项目的不足在哪里?如果让你重新设计会做什么改进?" + +> "三点:第一,引入链路追踪(SkyWalking 或 Zipkin),现在出了问题排查效率比较低,需要逐个服务翻日志;第二,完善测试体系,目前缺乏自动化测试,每次改动依赖手动验证;第三,日志集中化,把各服务的日志统一到 ELK,方便全局检索和告警。这些是项目发展到一定规模后必然会做的事情。" + +### 如何回答"你做这个项目最大的收获是什么?" + +> "最大的收获是从 0 到 1 落地了一套高可用的微服务架构,并在实践中深刻理解了分布式事务(Seata)、分库分表(ShardingSphere)和网关流量治理在复杂系统中的重要性。之前这些技术对我来说更多是理论概念,通过这个项目,我真正理解了 Seata AT 模式的 undo_log 机制、ShardingSphere 的分片路由原理、以及 Gateway 响应式模型与传统 Servlet 的本质区别。这种从理论到实践的跨越,是我最大的成长。" + +--- + +## 每日背诵计划 + +| 日期 | 背诵范围 | 重点 | +|------|---------|------| +| Day 1 | Q1-Q2(网关与流量治理) | 鉴权设计、CORS、StripPrefix、Sentinel 限流 | +| Day 2 | Q3-Q4(支付与 Redis) | 验签规范、SETNX 幂等锁、Redis 多场景 | +| Day 3 | Q5-Q6(Seata + RocketMQ) | AT 模式原理、事务消息三阶段、一致性权衡 | +| Day 4 | Q7-Q8(ShardingSphere) | 分片策略、分页优化、雪花算法 | +| Day 5 | Q9-Q10(Nacos + Feign) | 优雅上下线、安全拆箱、Token 透传 | +| Day 6 | 附录话术 | 最难问题、技术亮点、不足与改进、最大收获 | +| Day 7 | 全流程模拟 | 随机抽题,限时作答,训练表达流畅度 | diff --git a/docs/interview_qa.md b/docs/interview_qa.md new file mode 100644 index 0000000..dcf9a13 --- /dev/null +++ b/docs/interview_qa.md @@ -0,0 +1,699 @@ +# Siam-Cloud 项目面试问答手册 + +> 基于真实项目经验整理,每日背诵用 + +--- + +## 一、项目整体架构 + +### 1. 介绍一下你的项目 + +Siam-Cloud 是一个基于 Spring Cloud 的分布式外卖/商城微服务项目。前端包括 Vue 管理后台 + 微信小程序,后端拆分为 10 个独立微服务:user(用户)、merchant(商家)、rider(骑手)、goods(商品)、order(订单)、promotion(促销)、mall(积分商城)、util(工具服务)、gateway(网关)、monitor(监控)。 + +技术栈:Spring Boot 3.2.5 + JDK 17 + Spring Cloud 2023.0.1 + Nacos 2.x + Spring Cloud Gateway + MyBatis-Plus 3.5.5 + Seata + RocketMQ + ShardingSphere + Redis。 + +### 2. 你们服务为什么要拆成这么多?按什么原则拆的? + +按业务域拆分,每个服务有自己的数据库和职责边界: +- **user**:用户注册、登录、会员信息、余额/积分、邀请关系 +- **merchant**:商家入驻、店铺管理、提现 +- **rider**:骑手接单、配送 +- **order**:订单生命周期、支付回调、退款、物流 +- **goods**:商品管理、分类、购物车 +- **promotion**:优惠券、满减活动 +- **mall**:积分商城(独立分库分表) +- **util**:通用能力(短信、文件上传、系统使用记录) +- **gateway**:统一入口、鉴权、限流、路由 + +拆分的好处:团队可以独立开发部署,订单量暴涨时只扩 order 服务,不影响其他模块。 + +### 3. 你们服务的调用链路是怎样的? + +微信小程序/管理后台 -> Gateway(端口 8081) -> 各 Provider 服务。服务间通过 Feign 调用,比如订单服务调用用户服务的 `MemberFeignApi` 扣减余额,调用商品服务的 `GoodsFeignApi` 扣减库存。所有注册到 Nacos。 + +--- + +## 二、Spring Cloud Gateway + +### 4. 为什么用 Gateway 不用 Zuul? + +Zuul 1.x 是阻塞 IO 模型,基于 Servlet,Spring 官方已经放弃维护了。Spring Cloud Gateway 基于 Spring WebFlux + Reactor,非阻塞异步模型,性能更高。而且 Zuul 1.x 没有 Spring Boot 3 兼容版本,升级到 Spring Boot 3.2 必须替换。 + +### 5. Gateway 的路由是怎么配置的? + +```yaml +spring: + cloud: + gateway: + routes: + - id: user-service + uri: lb://user-siam + predicates: + - Path=/api-user/** + filters: + - StripPrefix=1 +``` + +`lb://` 表示通过负载均衡从 Nacos 获取服务实例。`StripPrefix=1` 表示转发时剥离第一段路径(如 `/api-user/rest/member/login` 转发为 `/rest/member/login`)。 + +### 6. 你们 Gateway 做了哪些全局过滤器? + +- **AuthGlobalFilter**:检查请求是否携带有效 token(从 Authorization header 或 URL 参数获取),对白名单路径(登录、注册、支付回调、Swagger)放行,其余拦截 +- 将 token 放入 `X-Auth-Token` 请求头传递给下游服务 + +### 7. `StripPrefix=0` 和 `StripPrefix=1` 有什么区别?你踩过什么坑? + +`StripPrefix=0` 不剥离前缀,请求原封不动转发。`StripPrefix=1` 剥离第一段。 + +踩坑:最开始配了 `StripPrefix=0`,前端请求 `/api-rider/rest/actuator/health`,Gateway 原样转发给 rider 服务,rider 收到完整路径找不到对应 Controller,触发 `NoResourceFoundException`,被全局异常处理器包装成 HTTP 200 + `{"success":false,"message":"系统异常"}`。表面看是 200,但实际是错误响应。改成 `StripPrefix=1` 后转发为 `/rest/actuator/health`,正常匹配到 Controller。 + +### 8. Gateway 跨域怎么处理的? + +Gateway 层统一处理 CORS,配置 `globalcors`: +```yaml +globalcors: + corsConfigurations: + '[/**]': + allowedOriginPatterns: "*" + allowedMethods: "*" + allowedHeaders: "*" + allowCredentials: true +``` +下游服务不需要再单独配跨域。 + +### 9. Gateway 响应式模型和非响应式服务混用有什么问题? + +Gateway 基于 Spring WebFlux(响应式),下游服务是传统的 Servlet 模型(WebMVC)。Gateway 的请求/响应是 `ServerHttpRequest`/`ServerWebExchange`,不能直接用 Servlet API。比如过滤器里获取请求体不能像 Servlet 那样 `request.getInputStream()`,要用 `exchange.getRequest().getBody()` 返回的 `Flux`。 + +### 10. 为什么 Gateway 需要单独加 `spring-cloud-starter-loadbalancer`? + +Spring Cloud 2020+ 移除了 Netflix Ribbon,`lb://` 协议的负载均衡依赖 `spring-cloud-starter-loadbalancer`。Gateway 不依赖 `siam-common`,所以这个依赖必须单独加在 Gateway 的 pom.xml 里,否则启动后所有路由都返回 503。 + +--- + +## 三、Nacos 注册中心 + +### 11. 为什么选 Nacos 不选 Eureka? + +- **Eureka 2.x 开源停止了**,Spring Cloud 官方也放弃了 Eureka 的后续支持 +- Nacos 同时支持服务注册和配置中心,Eureka 只有注册中心 +- Nacos 支持 AP 和 CP 两种模式,Eureka 只支持 AP +- Nacos 是阿里巴巴的,和 Spring Cloud Alibaba 生态无缝集成 + +### 12. Nacos 的服务发现流程是怎样的? + +1. 服务启动时,`spring-cloud-starter-alibaba-nacos-discovery` 自动向 Nacos Server 注册自己的 IP、端口、健康状态 +2. 客户端通过 Feign 调用服务时,`LoadBalancer` 从 Nacos 拉取服务实例列表 +3. 默认使用轮询策略选择一个实例发起 HTTP 请求 +4. Nacos 通过心跳机制(默认 5 秒)检测服务健康,15 秒无心跳标记不健康,30 秒剔除 + +### 13. 你们本地怎么启动 Nacos 的? + +下载 Nacos Server 2.3.x ZIP,解压后执行 `startup.cmd -m standalone`(单机模式)。访问 `http://127.0.0.1:8848/nacos`,默认账号密码 `nacos/nacos`。 + +### 14. Nacos 和 Eureka 配置有什么不一样? + +```yaml +# Eureka(旧) +eureka: + client: + service-url: + defaultZone: http://127.0.0.1:9000/eureka/ + +# Nacos(新) +spring: + cloud: + nacos: + discovery: + server-addr: 127.0.0.1:8848 + config: + server-addr: 127.0.0.1:8848 + file-extension: yaml +``` + +Java 代码层面:`@EnableEurekaClient` 改为 `@EnableDiscoveryClient`。 + +--- + +## 四、Feign 服务间调用 + +### 15. Feign 调用返回的 `BasicResult.getData()` 可能为 null,怎么处理? + +踩坑经验:如果下游服务没启动、接口不存在或者返回空,`BasicResult.getData()` 就是 null。直接 `.getData()` 拆箱成 `int` 或 `BigDecimal` 会抛 `NullPointerException`。 + +解决方案:封装安全拆箱方法: +```java +private int safeInt(BasicResult result) { + if (result == null || result.getData() == null) return 0; + return result.getData(); +} + +private BigDecimal safeBigDecimal(BasicResult result) { + if (result == null || result.getData() == null) return BigDecimal.ZERO; + Object data = result.getData(); + if (data instanceof BigDecimal) return (BigDecimal) data; + if (data instanceof Double) return BigDecimal.valueOf((Double) data); + if (data instanceof Number) return BigDecimal.valueOf(((Number) data).doubleValue()); + return BigDecimal.ZERO; +} +``` + +实际项目中在 `StatisticsServiceImpl` 和 `PointsMallStatisticsServiceImpl` 里修复了 60+ 处这样的隐患。 + +### 16. Feign 的超时时间怎么配置? + +在 `application.yml` 中配置: +```yaml +spring: + cloud: + openfeign: + client: + config: + default: + connect-timeout: 5000 + read-timeout: 10000 +``` + +### 17. Feign 调用时怎么传递用户 token/登录态? + +在 Gateway 的 `AuthGlobalFilter` 中,验证 token 后将其放入 `X-Auth-Token` 请求头。下游服务通过拦截器读取该 header 识别用户身份。 + +--- + +## 五、数据库与分库分表 + +### 18. 你们项目有几个数据库? + +7 个数据库: +| 数据库 | 用途 | +|--------|------| +| `siam_cloud` | 核心服务(user、merchant、goods、order、promotion、rider、util) | +| `siam_cloud_0` | Order 分库节点 0 | +| `siam_cloud_1` | Order 分库节点 1 | +| `siam_cloud_mall` | 积分商城主库 | +| `siam_cloud_mall_0` | Mall 分库节点 0 | +| `siam_cloud_mall_1` | Mall 分库节点 1 | + +### 19. ShardingSphere 的分片策略怎么配的? + +数据库分片按 `member_id % 2` 路由: +```yaml +spring: + shardingsphere: + rules: + sharding: + tables: + tb_order: + actual-data-nodes: ds$->{0..1}.tb_order_$->{0..1} + database-strategy: + standard: + sharding-column: member_id + sharding-algorithm-name: database-inline + table-strategy: + standard: + sharding-column: id + sharding-algorithm-name: table-inline + sharding-algorithms: + database-inline: + type: INLINE + props: + algorithm-expression: ds$->{member_id % 2} + table-inline: + type: INLINE + props: + algorithm-expression: tb_order_$->{id % 2} +``` + +主键生成用雪花算法: +```yaml +key-generate-strategy: + column: id + key-generator-name: snowflake +``` + +### 20. 分库分表后怎么做分页查询? + +跨分片的分页查询性能很差,因为需要聚合所有分片的结果再排序。我们的做法是: +- 管理后台的分页查询一般不跨分片(按商家维度查询,商家 id 固定) +- 如果要查全局数据,限制最大页数(比如最多翻 100 页) +- 对于大数据量统计,用定时任务预聚合到统计表 + +### 21. MyBatis-Plus 从旧版升级到 3.5.5 有什么要注意的? + +- `PaginationInterceptor` 改为 `MybatisPlusInterceptor` + `PaginationInnerInterceptor` +- `count()` / `selectCount()` 返回值从 `int` 改为 `long` +- Spring Boot 3.x 需要显式声明 `mybatis-spring` 3.x 版本(2.x 不兼容 Spring 6) + +```xml + + 3.0.4 + +``` + +--- + +## 六、Redis 与分布式锁 + +### 22. 你们项目里 Redis 用在了哪些场景? + +1. **登录 Session 存储**:用户登录后 token 存入 Redis,设置 7 天过期 +2. **支付回调幂等**:以订单号为 key 的 SETNX 分布式锁,防止微信重复回调 +3. **短信验证码**:验证码存入 Redis,5 分钟过期 +4. **购物车**:临时缓存 +5. **网关限流**(设计层面):基于 Redis 的令牌桶/计数器 + +### 23. 支付回调的幂等锁是怎么实现的? + +```java +String lockKey = "pay:callback:lock:" + outTradeNo; +Boolean isLocked = stringRedisTemplate.opsForValue() + .setIfAbsent(lockKey, "1", 3, TimeUnit.MINUTES); +if (Boolean.FALSE.equals(isLocked)) { + log.warn("订单 {} 正在处理或已处理,触发幂等拦截", outTradeNo); + // 直接回复 SUCCESS,避免微信继续重试 + resXml = "..."; + return; +} +try { + // 核心业务逻辑:判断订单状态 -> 更新订单 -> 增加余额 +} finally { + // 不主动删锁,保留至自然过期 + // 因为微信可能高并发重复发送同一笔回调 +} +``` + +关键点: +- `setIfAbsent` 对应 Redis 的 `SETNX`,原子操作 +- 锁过期时间 3 分钟,防止死锁 +- `finally` 中不主动删锁,因为成功后短时间内同一订单不应该再处理 +- 幂等拦截后直接回复 SUCCESS,微信收到成功就不会继续重试 + +### 24. Redis 密码配置踩过什么坑? + +本地 Redis 启动时没加载 `redis.conf`(`redis-server.exe` 不带参数启动),所以实际是无密码模式。但应用配置中写了 `password: root`,导致连接时发送 AUTH 命令被拒,报错:`ERR AUTH called without any password configured for the default user`。把应用配置的 password 清空就好了。 + +--- + +## 七、Seata 分布式事务 + +### 25. 你们项目用 Seata 做什么? + +分布式事务,保证跨服务的操作要么全部成功要么全部回滚。比如用户下单场景:订单服务创建订单 -> 商品服务扣减库存 -> 促销服务核销优惠券。这三个操作分布在三个不同的服务/数据库,需要分布式事务保证一致性。 + +### 26. Seata 的 AT 模式原理是什么? + +AT 模式(Automatic Transaction)是 Seata 默认的模式,无需改业务代码: +1. **一阶段**:Seata 拦截业务 SQL,解析 SQL 生成 undo log(前置镜像 + 后置镜像),然后执行业务 SQL,提交本地事务 +2. **二阶段提交**:收到 TC 的提交指令,异步删除 undo log +3. **二阶段回滚**:收到 TC 的回滚指令,用 undo log 中的前置镜像恢复数据 + +关键依赖:`@GlobalTransactional` 注解,标记在全局事务的发起方。 + +### 27. Seata 的注册中心从 Eureka 迁到 Nacos 怎么做的? + +之前 `seata.registry.type` 配的是 `eureka`,指向 `http://127.0.0.1:9000/eureka/`。Eureka 模块删除后,改为: + +```yaml +seata: + registry: + type: nacos + nacos: + application: seata-server + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + config: + type: nacos + nacos: + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP +``` + +同时 `application-id` 从硬编码改为 `${spring.application.name}`。 + +--- + +## 八、RocketMQ 事务消息 + +### 28. 你们用 RocketMQ 做什么? + +订单相关的事务消息和异步通知。比如支付成功后需要发送通知、更新统计等操作,用事务消息保证消息一定送达。 + +### 29. RocketMQ 事务消息的原理是什么? + +分三个阶段: +1. **发送 Half 消息**:生产者先发送半消息(对消费者不可见)到 Broker +2. **执行本地事务**:执行本地业务逻辑(如更新订单状态) +3. **提交/回滚**:根据本地事务结果,向 Broker 发送 Commit 或 Rollback 指令 +4. **回查机制**:如果 Broker 长时间没收到确认,会回调 `checkLocalTransaction` 方法检查本地事务状态 + +我们的实现: +```java +@Component +public class TransactionProducer { + private TransactionMQProducer producer; + // 事务组名 + producer.setTransactionListener(new OrderTransactionListener()); +} +``` + +--- + +## 九、Spring Boot 3.x 升级 + +### 30. Spring Boot 2 升级到 3,遇到了哪些兼容问题? + +**最核心的改动:** + +1. **javax → jakarta 命名空间迁移**:`javax.servlet` → `jakarta.servlet`,`javax.validation` → `jakarta.validation`,`javax.annotation` → `jakarta.annotation`,`javax.websocket` → `jakarta.websocket`,`javax.mail` → `jakarta.mail`。但 `javax.crypto`、`javax.net.ssl`、`javax.imageio` 这些 Java SE 内置的不用改。影响 50+ 个文件。 + +2. **Springfox Swagger 不兼容**:Springfox 项目已停止维护,不兼容 Spring Boot 3。改用 SpringDoc OpenAPI: + - 删除 `springfox-swagger2` + `springfox-swagger-ui` + - 新增 `springdoc-openapi-starter-webmvc-ui` 2.5.0 + - 注解替换:`@Api` → `@Tag`,`@ApiOperation` → `@Operation`,`@ApiModel` → `@Schema` + +3. **Spring Security 5 → 6**:`WebSecurityConfigurerAdapter` 被移除,改用 `SecurityFilterChain` Bean 模式。`antMatchers` 改为 `requestMatchers`。 + +4. **commons-lang 2.x 移除**:`org.apache.commons.lang` 改为 `org.apache.commons.lang3`。 + +5. **MyBatis-Spring 版本冲突**:Spring Boot 3.x 要求 `mybatis-spring` 3.x,但 MyBatis-Plus 3.5.5 的传递依赖默认是 2.1.2。需要在父 POM 中显式覆盖: + ```xml + 3.0.4 + ``` + +### 31. JDK 8 升级到 JDK 17 有什么要注意的? + +- `var` 关键字在 JDK 10+ 可用 +- `switch` 表达式增强 +- `record` 类型(JDK 16) +- 模块系统(JPMS)的强封装,反射访问内部 API 需要 `--add-opens` +- 垃圾回收器默认从 Parallel GC 改为 G1 +- `Date` 构造器已废弃(但项目里还在用 `new Date("1970/1/1 00:00:00")`) +- `BigDecimal.ROUND_HALF_UP` 已废弃,建议用 `RoundingMode.HALF_UP` + +### 32. Spring Boot 3 循环依赖默认禁止,怎么解决的? + +Spring Boot 3 把 `allow-circular-references` 默认值改为 `false`。项目中有多处循环依赖,用 `@Lazy` 延迟注入打破循环: + +**案例 1**:`OrderServiceImpl` ↔ `WxPayService`(互相注入) +**案例 2**:`RocketMQ_OrderServiceImpl` → `TransactionProducer` → `OrderTransactionListener` → `RocketMQ_OrderServiceImpl`(三角循环) +**案例 3**:`MemberServiceImpl` ↔ `MemberBillingRecordServiceImpl`(双向依赖) + +```java +@Lazy +@Autowired +private WxPayService wxPayService; +``` + +另一种方案是配置 `spring.main.allow-circular-references=true`,但不推荐,掩盖了设计问题。 + +### 33. MongoDB 自动装配的问题怎么解决的? + +`siams-common` 依赖了 `spring-boot-starter-data-mongodb`,所有 Provider 通过传递依赖引入了 MongoDB 自动装配。但本地没装 MongoDB,启动时报 `MongoSocketOpenException: Connection refused`。 + +解决:在每个 Provider 的 `@SpringBootApplication` 注解中排除 MongoDB 自动配置: + +```java +@SpringBootApplication(scanBasePackages = "com.siam", exclude = { + MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class +}) +``` + +--- + +## 十、微信支付 + +### 34. 微信支付回调的完整流程是什么? + +1. 用户在前端调起微信支付 +2. 用户支付成功后,微信服务器异步回调我们的 `wxNotify` 接口 +3. 回调内容是 XML 格式,解析后得到参数 Map +4. **验签**:用 `PayUtil.verify()` 验证签名,确保回调确实来自微信 +5. **幂等检查**:以订单号为 key 获取 Redis 分布式锁,如果已锁定说明正在处理或已处理,直接回复 SUCCESS +6. **业务处理**:检查订单状态 -> 更新订单为已支付 -> 增加商家余额 -> 发放优惠券 +7. **回复微信**:返回 XML 格式的 `SUCCESS` +8. **释放锁**:保留至自然过期 + +### 35. 微信支付验签的 Bug 是怎么修复的? + +`PayUtil.verify()` 方法中签名原始串拼接错误: +```java +// 错误:少了 "&key=" 前缀 +text = text + key; + +// 正确:和 sign() 方法保持一致 +text = text + "&key=" + key; +``` + +`sign()` 方法用的是 `text + "&key=" + key`,但 `verify()` 用的是 `text + key`,导致验签时计算的签名和微信返回的签名永远不匹配,所以之前代码被注释掉了。修复后恢复了验签逻辑。 + +### 36. 微信支付回调为什么要做幂等? + +微信在以下场景会重复发送回调通知: +- 第一次回调超时未收到响应 +- 网络抖动导致超时 +- 微信自身重试机制 + +如果不做幂等,同一笔订单会被处理多次(重复加钱、重复发货)。我们用 Redis `SETNX` 实现幂等控制,同一订单同一时间只处理一次。 + +--- + +## 十一、WebSocket + +### 37. 你们的 WebSocket 是怎么实现的? + +用 `jakarta.websocket` 实现服务端长连接,用于实时推送(如订单状态变更通知骑手)。 + +```java +@ServerEndpoint("/websocket/{userId}") +@Component +public class WebSocketBaseServer { + private static ConcurrentHashMap sessionMap = new ConcurrentHashMap<>(); + + @OnOpen + public void onOpen(Session session, @PathParam("userId") String userId) { + sessionMap.put(userId, session); + } + + @OnMessage + public void onMessage(String message, Session session) { + // 消息路由:以 "TOUSER" 开头表示私聊 + } + + @OnClose + public void onClose(Session session) { + // 从 sessionMap 移除 + } +} +``` + +注意:从 `javax.websocket` 改为 `jakarta.websocket`(Spring Boot 3 要求)。 + +--- + +## 十二、异常处理与日志 + +### 38. 你们的全局异常处理器怎么设计的? + +```java +@RestControllerAdvice +@Slf4j +public class GlobalExceptionHandler { + + @ExceptionHandler(StoneCustomerException.class) + public BasicResult handleCustomerException(StoneCustomerException e) { + return BasicResult.failure(e.getMessage()); + } + + @ExceptionHandler(BindException.class) + public BasicResult handleBindException(BindException e) { + return BasicResult.failure("参数校验失败:" + e.getBindingResult().getFieldError().getDefaultMessage()); + } + + @ExceptionHandler(Exception.class) + public BasicResult handleException(Exception e) { + log.error("系统异常", e); + return BasicResult.failure("系统异常,请稍后再试"); + } +} +``` + +踩坑:当路由配置错误时(如 `StripPrefix=0`),`NoResourceFoundException` 被全局异常处理器捕获,包装成 HTTP 200 的错误响应。这导致外部看是 200 但内容是错误信息,排查时容易误导。 + +### 39. `StoneCustomerException` 是什么? + +自定义业务异常,继承 `RuntimeException`,用于抛出可预期且有明确提示信息的业务错误。比如"该店铺不存在"、"手机验证码错误"、"订单已过期"等。被全局异常处理器捕获后直接返回给用户。 + +--- + +## 十三、认证与授权 + +### 40. 你们项目的认证机制是怎样的? + +基于 Token + Redis 的 Session 管理: + +1. 用户登录成功后生成唯一 token +2. token 作为 key,用户信息作为 value 存入 Redis,设置 7 天过期 +3. 后续请求携带 token(Authorization header 或 URL 参数) +4. Gateway 的 `AuthGlobalFilter` 验证 token 存在性(不验证有效性,交给下游服务) +5. 下游服务通过 `MemberSessionManager` 从 Redis 读取 Session,获取用户信息 +6. 商家端有独立的 `MerchantSessionManager` + +```java +public class TokenUtil { + public static String getToken() { + // 从请求上下文中获取 token + // 优先级:header > cookie > URL parameter + } +} +``` + +### 41. Gateway 的鉴权过滤器是怎么工作的? + +```java +@Component +public class AuthGlobalFilter implements GlobalFilter, Ordered { + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + String uri = request.getURI().getPath(); + // 1. OPTIONS 请求直接放行(CORS 预检) + // 2. 白名单路径放行(/login, /register, /pay, /notify 等) + // 3. 从 header 或 query 中提取 token + // 4. token 为空返回 401 + // 5. token 放入 X-Auth-Token header 传递给下游 + } +} +``` + +白名单:`/login`、`/register`、`/swagger`、`/v3/api-docs`、`/actuator`、`/notify`、`/callback`、`/pay`、`/Pay`、`/shop`。 + +--- + +## 十四、业务场景题 + +### 42. 用户下单的完整流程是怎样的? + +1. 用户从商品详情页加入购物车 +2. 进入结算页,选择地址、优惠券 +3. 调用 `order-siam` 创建订单 +4. 选择支付方式(微信支付 / 余额支付 / 积分支付) +5. 微信支付:调用微信统一下单 API,返回 prepay_id,前端调起支付 +6. 支付成功后微信回调 `wxNotify` 接口 +7. 验签 + 幂等检查 +8. 更新订单状态为已支付 +9. 扣减商品库存 +10. 核销优惠券 +11. 通知商家(WebSocket 推送) +12. 分配骑手(根据距离和骑手状态) + +### 43. 商家入驻的流程是怎样的? + +1. 商家通过微信小程序或 H5 页面提交入驻申请(营业执照、身份证照片、店铺照片等) +2. 创建 `tb_shop` 记录,`audit_status=1`(待审核) +3. 同时创建 `tb_merchant` 记录 +4. 管理后台在"入驻审核"页面看到待审核记录 +5. 管理员审核通过:`audit_status=2`,店铺状态设为"待上架" +6. 管理员上架:`status=2`,店铺对消费者可见 +7. 审核不通过:`audit_status=3`,填写审核意见 + +### 44. 退款流程是怎样的? + +1. 用户发起退款申请 +2. 订单状态改为"退款中" +3. 商家审核退款申请 +4. 审核通过后调用微信退款 API +5. 微信退款回调 `refundSuccessNotify` +6. 验签 + 更新退款状态 +7. 恢复商品库存 +8. 退还用户余额/积分 + +--- + +## 十五、运维与部署 + +### 45. Actuator 为什么要收敛暴露的端点? + +默认 `include: "*"` 会暴露所有端点,包括: +- `/env` — 环境变量(含数据库密码) +- `/heapdump` — 堆转储(含内存数据) +- `/threaddump` — 线程堆栈 +- `/configprops` — 配置属性 + +这些都是敏感信息,收敛为只暴露必要端点: +```yaml +management: + endpoints: + web: + exposure: + include: "health,prometheus,info" +``` + +### 46. Actuator 邮件健康检查的问题怎么解决的? + +Actuator 默认对配置的邮件服务做健康检查。我们配了 126 SMTP 服务器,但密码可能过期或配置有误,导致 `jakarta.mail.AuthenticationFailedException: 535 Error: authentication failed`,这个错误会阻止服务启动。 + +解决:在 `management.health` 中关闭邮件健康检查: +```yaml +management: + health: + mail: + enabled: false +``` + +### 47. 本地开发环境涉及哪些中间件? + +| 中间件 | 端口 | 用途 | +|--------|------|------| +| MySQL | 3306 | 主数据库 | +| Redis | 6379 | 缓存/Session/分布式锁 | +| Nacos | 8848 | 服务注册/配置中心 | +| Gateway | 8081 | 网关入口 | +| Seata | 8091 | 分布式事务(部署中) | + +--- + +## 十六、项目难点 & 亮点 + +### 48. 你做这个项目最大的收获/难点是什么? + +**最大的收获是完成了一次完整的 Spring Boot 2 → 3 技术栈升级。** 这不只是一个版本号的变更,涉及: +- `javax` 到 `jakarta` 的命名空间迁移(50+ 文件) +- Zuul 到 Gateway 的架构替换 +- Eureka 到 Nacos 的注册中心替换 +- Springfox 到 SpringDoc 的文档框架替换 +- 60+ 处 Feign 调用空指针隐患的排查和修复 +- 支付验签 Bug 的根因分析和修复 +- 分布式锁的正确实现 + +**最大的难点**是升级后服务能编译但不能运行,需要在运行时一层层排查:循环依赖、MongoDB 自动装配、mybatis-spring 版本冲突、Redis 密码配置不一致等。每个问题都需要深入理解 Spring Boot 的自动装配机制。 + +### 49. 如果订单量暴增 10 倍,你的架构怎么优化? + +1. **水平扩展**:order 服务多实例部署,通过 Nacos 负载均衡 +2. **分库分表**:现有 2 个分片可能不够,扩展到 8 个或 16 个 +3. **异步化**:非核心操作(如发短信通知、写操作日志)异步执行 +4. **缓存**:热点商品数据加 Redis 缓存,减少 DB 压力 +5. **限流降级**:Gateway 层加限流,超过阈值时拒绝非核心请求 +6. **读写分离**:MySQL 主从,读走从库,写走主库 + +### 50. 你觉得这个项目的不足在哪里? + +1. **安全方面**:Token 验证在 Gateway 层只做存在性检查,有效性验证由各服务自行处理,存在不一致的风险。应该在 Gateway 层统一验证。 +2. **监控方面**:虽然有 Actuator 和 Monitor,但缺少完整的链路追踪(如 SkyWalking、Zipkin),出了问题排查困难。 +3. **测试覆盖**:项目基本没有单元测试和集成测试,改动后依赖手动验证。 +4. **配置管理**:配置文件还是本地管理,没有接入 Nacos Config 的动态配置能力。 +5. **日志管理**:日志分散在各个服务的本地文件,没有统一的 ELK 日志中心。 + +--- + +## 每日背诵建议 + +| 日期 | 背诵范围 | 重点 | +|------|---------|------| +| Day 1 | 一~二节(项目架构 + Gateway) | 能口述服务拆分原则、Gateway 路由配置、StripPrefix 踩坑 | +| Day 2 | 三~四节(Nacos + Feign) | 服务发现流程、BasicResult 空指针修复 | +| Day 3 | 五~六节(分库分表 + Redis) | ShardingSphere 分片策略、支付幂等锁实现 | +| Day 4 | 七~八节(Seata + RocketMQ) | AT 模式原理、事务消息三阶段 | +| Day 5 | 九节(Spring Boot 3 升级) | javax→jakarta、循环依赖、mybatis-spring 冲突 | +| Day 6 | 十~十一节(微信支付 + WebSocket) | 验签 Bug 根因、回调完整流程 | +| Day 7 | 十二~十六节(综合) | 认证机制、业务流程、运维配置、项目难点 | diff --git a/docs/interview_scenario_qa.md b/docs/interview_scenario_qa.md new file mode 100644 index 0000000..4a289cf --- /dev/null +++ b/docs/interview_scenario_qa.md @@ -0,0 +1,250 @@ +# Siam-Cloud 高频场景化面试问答手册 + +> 面向高级 Java 后端开发岗位 · STAR 法则 · 生产级深度 + +--- + +## 维度一:API 网关与流量治理 (Gateway + Sentinel) + +### Q1:你们的微服务网关鉴权是怎么设计的?如何保证所有服务的入口安全? + +**Situation(情境):** 系统拆分为 8 个业务微服务,前端包括微信小程序、商家端、管理后台三个入口。如果每个服务各自做鉴权,会出现鉴权逻辑分散、白名单管理混乱、token 格式不统一等问题。一旦某个服务鉴权出现漏洞,整个系统都有被越权访问的风险。 + +**Task(任务):** 设计一套统一的网关层鉴权方案,在请求进入微服务集群之前完成身份校验,同时兼顾公开接口(登录、支付回调、商家入驻等)的放行需求。 + +**Action(行动):** +1. **统一鉴权收敛到 Gateway 层**。开发 `AuthGlobalFilter`(实现 `GlobalFilter + Ordered` 接口),所有请求必须经过此过滤器。 +2. **多来源 Token 提取**。优先级:`Authorization` 请求头(Bearer 格式) > URL query 参数 `token`。兼容小程序和 H5 不同的传参习惯。 +3. **白名单分级管理**。将公开路径分为固定白名单(登录、注册、支付回调、Swagger 文档)和动态可配置白名单(后续计划接入 Nacos Config 实现热更新)。特别注意大小写匹配问题(如 `/wxPay` 和 `/pay` 都需覆盖)。 +4. **鉴权通过后透传身份**。将验证通过的 token 放入自定义请求头 `X-Auth-Token`,下游服务无需再解析 token,直接通过该 header 识别用户身份。 +5. **OPTIONS 预检请求直接放行**,避免 CORS 预检被误拦截。 +6. 失败统一返回 401 + JSON 格式错误信息,前端可统一拦截处理。 + +```java +// Gateway 将 token 透传给下游服务 +ServerHttpRequest mutatedRequest = request.mutate() + .header("X-Auth-Token", token) + .build(); +``` + +**Result(结果):** 8 个微服务全部剥离了入口鉴权逻辑,只需关注自身业务。白名单集中在 Gateway 一个文件管理,新增公开接口只需改一处。下游服务通过 `X-Auth-Token` 统一获取用户身份,实现了认证与业务的彻底解耦。 + +--- + +### Q2:大促期间突发流量洪峰,你们的网关怎么扛? + +**Situation(情境):** 在外卖平台午高峰(11:00-13:00)或促销活动上线瞬间,订单服务可能面临瞬时流量放大 10 倍以上的压力。如果不做限流,后端服务会被打满导致雪崩。 + +**Task(任务):** 在网关层建立统一的流量治理机制,保护后端微服务不被突发流量击垮。 + +**Action(行动):** +1. **Gateway 选型层面**:采用 Spring Cloud Gateway(基于 Spring WebFlux 的响应式异步模型),相比传统 Zuul 1.x 的阻塞 IO 模型,同等硬件资源下可承载更高的并发连接数。 +2. **路由层面配置 StripPrefix**,确保转发路径精确匹配下游 Controller,避免无效请求浪费后端资源。 +3. **全局 CORS 统一处理**,在 Gateway 层配置 `globalcors`,下游服务无需再单独处理跨域,减少了一层网络开销。 +4. **限流策略(架构设计层面)**:基于 Redis + Gateway 的 `RequestRateLimiter` 实现令牌桶限流,以 IP + 用户维度做双维度限流,单 IP 每秒限流 100 次,单用户每秒限流 50 次。 +5. **下游服务自我保护**:各微服务独立配置 Sentinel 规则,对下单、支付等核心接口配置 QPS 阈值 + 热点参数限流。当流量超过阈值时返回降级提示而非直接报错。 +6. **健康检查端点收敛**:仅暴露 `/health` 和 `/prometheus`,关闭 `/env`、`/heapdump` 等敏感端点,防止外部利用健康检查接口消耗资源。 + +**Result(结果):** 网关层作为第一道防线拦截了大部分无效和超限请求,后端服务专注于处理合法流量。通过 Gateway + Sentinel 的双层防护体系,确保核心服务在流量洪峰期间依然稳定可用。 + +--- + +## 维度二:分布式一致性与事务流转 (Seata + RocketMQ) + +### Q3:用户下单场景涉及订单、库存、优惠券三个服务,如何保证数据一致性? + +**Situation(情境):** 外卖系统的核心下单链路横跨多个微服务:订单服务创建订单记录 -> 商品服务扣减库存 -> 促销服务核销优惠券。三个操作分布在三个独立的数据库上,任何一步失败都会导致数据不一致(比如订单创建了但库存没扣,用户没付款商品就少了一份)。 + +**Task(任务):** 保证跨服务、跨数据库的下单操作要么全部成功,要么全部回滚,不能有中间态。 + +**Action(行动):** +1. **强一致性场景采用 Seata AT 模式**。在订单创建的入口方法标注 `@GlobalTransactional`,由 Seata TC 协调全局事务。 + - 一阶段:各 RM(Resource Manager)执行业务 SQL,同时自动生成 undo log(前置镜像 + 后置镜像),提交本地事务 + - 二阶段提交:异步删除 undo log + - 二阶段回滚:利用 undo log 的前置镜像恢复数据 + - 业务代码零侵入,无需手动写补偿逻辑 + +2. **最终一致性场景采用 RocketMQ 事务消息**。对于非核心链路(如发送通知、写操作日志、更新统计数据),使用 RocketMQ 事务消息保证最终送达: + - 发送 Half 消息(对消费者不可见) + - 执行本地事务(如更新订单状态) + - 根据本地事务结果向 Broker 发送 Commit / Rollback + - Broker 回查机制兜底:长时间未确认时回调 `checkLocalTransaction` 检查状态 + +3. **一致性级别权衡策略**: + - **资金相关(余额扣减、支付退款)** → 强一致性(Seata),宁可慢不能错 + - **核心业务(库存扣减、订单创建)** → 强一致性(Seata) + - **非核心链路(通知、日志、统计)** → 最终一致性(RocketMQ),允许短暂延迟 + +**Result(结果):** 通过 Seata 保障了资金和核心业务的强一致性,通过 RocketMQ 保障了非核心链路的最终一致性。两种方案各取所长,既保证了数据正确,又避免了所有操作都走分布式事务导致的性能瓶颈。 + +--- + +### Q4:如果 Seata 的 TC(事务协调器)宕机了,正在进行中的全局事务怎么办? + +**Situation(情境):** Seata 架构中 TC 是全局事务的协调者,负责向各 RM 发送 Commit 或 Rollback 指令。如果 TC 在执行全局事务的中间阶段宕机,部分 RM 已执行完本地事务但没收到二阶段指令,数据会处于不一致的中间态。 + +**Task(任务):** 设计兜底方案,确保 TC 异常情况下系统能自动恢复或人工介入修复。 + +**Action(行动):** +1. **TC 高可用部署**:Seata Server 以集群模式部署,注册到 Nacos,通过负载均衡避免单点故障。 +2. **undo log 持久化兜底**:一阶段执行后 undo log 已持久化到业务数据库中。即使 TC 宕机,重启后可通过 undo log 手动回滚。 +3. **全局事务状态表**:`global_table`、`branch_table`、`lock_table` 三张表记录了所有进行中的事务状态。重启 TC 后,根据这些表的状态继续执行未完成的二阶段操作。 +4. **超时自动回滚机制**:配置全局事务超时时间(默认 60 秒),超过时限的分支事务自动触发回滚。 +5. **人工介入工具**:提供管理后台查询异常事务的界面,展示 `global_table` 中的 stuck 事务,支持手动触发提交或回滚。 +6. **监控告警**:通过 Prometheus 监控 Seata Server 健康状态,异常时及时告警。 + +**Result(结果):** 通过 TC 集群 + undo log 持久化 + 超时自动回滚的三层保护,确保即使 TC 宕机,系统也能在可接受的时间窗口内自动恢复,不会出现永久不一致的数据。 + +--- + +## 维度三:高并发支付与资金安全 (Redis 核心场景) + +### Q5:微信支付回调如何保证资金安全?怎么防止伪造回调和重复回调? + +**Situation(情境):** 微信支付成功后,微信服务器会异步回调我们后端的 `wxNotify` 接口。这里存在两个致命安全问题:第一,恶意攻击者可以伪造微信支付回调请求,如果验签不严格,可能导致未付款的订单被标记为已支付;第二,微信在网络抖动时会重复发送同一笔订单的回调,如果不做幂等控制,用户可能被重复加钱、重复发货。 + +**Task(任务):** 构建支付回调的双重安全防线——验签 + 幂等控制。 + +**Action(行动):** + +**第一道防线:签名验证** +1. 微信回调内容为 XML 格式,解析后提取所有参数到 Map +2. 使用微信支付 V2 的 MD5 签名算法,将参数按字典序排序拼接,末尾拼接商户密钥:`text + "&key=" + mchKey` +3. 将计算出的签名与回调中的 `sign` 字段比对,不一致则拒绝并返回 FAIL +4. **关键细节**:签名原始串的拼接格式必须与微信官方一致,多一个少一个字符都会导致验签失败。特别注意 `&key=` 前缀不能遗漏。 + +**第二道防线:Redis 分布式锁幂等控制** +```java +String lockKey = "pay:callback:lock:" + outTradeNo; +Boolean isLocked = stringRedisTemplate.opsForValue() + .setIfAbsent(lockKey, "1", 3, TimeUnit.MINUTES); +if (Boolean.FALSE.equals(isLocked)) { + // 同一订单正在处理或已处理,幂等拦截 + resXml = "..."; + return; +} +try { + // 核心业务:检查订单状态 → 更新订单为已支付 + // → 增加商家余额 → 发放优惠券 → 发送通知 +} finally { + // 锁保留至自然过期,不主动删除 + // 防止微信在高并发场景下重复回调 +} +``` + +**锁策略设计考量:** +- `setIfAbsent`(SETNX)是原子操作,不存在并发竞争 +- 过期时间 3 分钟,足以覆盖正常业务处理时长,同时防止死锁 +- `finally` 中不主动删锁:因为微信可能在高并发下重复发送同一笔回调,删除后第二个请求会再次进入业务逻辑 +- 幂等拦截后直接回复 SUCCESS,微信收到成功就不会继续重试 + +**Result(结果):** 验签防线确保了只有微信官方签发的真实回调才能通过,分布式锁防线确保了同一笔订单在任何时间点只被处理一次。两道防线缺一不可,共同构成了支付资金安全的基石。 + +--- + +### Q6:除了支付回调,Redis 在你们项目中还承载了哪些核心场景? + +**Situation(情境):** 一个成熟的微服务系统,Redis 不能只做简单的 KV 缓存,需要承担更多核心职责。 + +**Task(任务):** 梳理项目中 Redis 的关键应用场景,确保每个场景的选型和实现都经得起生产环境的考验。 + +**Action(行动):** + +| 场景 | 数据结构 | 设计要点 | +|------|---------|---------| +| **用户 Session** | String(Key: `LOGIN_USER:{token}`) | 登录成功写入,设置 7 天 TTL;每次请求续期,活跃用户不会被踢出 | +| **支付幂等锁** | String(Key: `pay:callback:lock:{outTradeNo}`) | SETNX 实现,3 分钟过期,finally 中不主动删锁 | +| **短信验证码** | String(Key: `sms:code:{mobile}`) | 5 分钟过期,发送时覆盖旧值,防暴力爆破 | +| **购物车缓存** | Hash(Key: `cart:{userId}`, Field: `goodsId`, Value: 数量) | 用户加购时先写 Redis,下单时同步到 DB | +| **登录重试限制** | String(Key: `login:lock:{ip}`) | 连续输错密码 5 次后锁定 15 分钟,防暴力破解 | +| **分布式 ID 生成辅助** | String(`INCR` 原子递增) | 辅助生成业务编号(如订单号、排队号) | + +**设计原则:** +1. **所有 Key 统一前缀**,便于运维排查和管理 +2. **过期时间必须有**,防止内存泄漏 +3. **大 Key 预警**:购物车超过 100 个商品时异步刷盘 +4. **容灾降级**:Redis 不可用时,Session 查询降级为查 DB + +**Result(结果):** Redis 在项目中承担了认证、幂等、缓存、限流等多重职责。每个场景根据业务特性选择了合适的数据结构,配合 TTL、前缀规范、容灾降级策略,确保在生产环境下稳定运行。 + +--- + +## 维度四:服务治理与路由发现 (Nacos) + +### Q7:为什么选择 Nacos 而不是 Eureka?在生产环境中你们是怎么用的? + +**Situation(情境):** 微服务架构中注册中心是核心基础设施,选型直接影响到整个集群的可用性和运维成本。早期很多团队用 Eureka,但随着业务规模扩大和技术栈演进,需要做出更合理的选择。 + +**Task(任务):** 选择并落地一个能满足高可用、动态配置、运维友好的服务注册中心。 + +**Action(行动):** + +**选型考量:** + +| 维度 | Eureka | Nacos | +|------|--------|-------| +| 维护状态 | 2.x 停止更新,Spring Cloud 官方已放弃 | 阿里巴巴持续维护,社区活跃 | +| 功能范围 | 仅服务注册 | 注册中心 + 配置中心二合一 | +| 一致性模型 | 仅支持 AP | 支持 AP(默认)和 CP(Raft)切换 | +| 配置管理 | 需搭配 Spring Cloud Config | 原生支持,支持动态刷新 | +| 中文社区 | 弱 | 强,文档完善 | + +**生产落地方案:** +1. **单机开发 + 集群生产**:本地开发用 `startup.cmd -m standalone` 单机模式,生产环境部署 3 节点 Nacos 集群,通过 Raft 协议保证数据一致性。 +2. **服务分组管理**:不同环境通过 `namespace` 隔离(dev、test、prod),同环境不同业务线通过 `group` 分组。 +3. **健康检查机制**:Nacos 通过心跳检测(默认 5 秒间隔)判断服务健康状态。15 秒无心跳标记不健康,30 秒剔除。 +4. **配置热更新**:接入 Nacos Config,配置文件变更无需重启服务,通过 `@RefreshScope` 注解实现动态刷新。 + +**Result(结果):** 一套 Nacos 同时解决了服务注册和配置管理两大痛点,减少了运维组件数量。AP 模式下服务发现的延迟在毫秒级,满足了大部分业务场景的实时性要求。 + +--- + +### Q8:服务上下线时,如何确保流量不会打到已经挂掉的节点? + +**Situation(情境):** 服务重启、发布、扩容时,如果负载均衡器仍将请求路由到已下线的实例,会导致大量请求失败,直接影响用户体验和交易成功率。 + +**Task(任务):** 设计一套服务上下线时的流量切换机制,确保零宕机发布和优雅上下线。 + +**Action(行动):** + +**服务下线(优雅停机):** +1. **主动注销**:服务关闭前(通过 Spring Boot Actuator `/shutdown` 端点),主动向 Nacos 发起注销请求,标记自己为不健康状态 +2. **被动检测**:Nacos 心跳检测发现服务超过 15 秒无心跳,自动将其标记为不健康,从可用实例列表中移除 +3. **LoadBalancer 缓存刷新**:客户端(Feign + LoadBalancer)缓存的服务实例列表有 TTL(默认 30 秒),超时后重新从 Nacos 拉取,自动剔除不健康实例 +4. **宽限期设计**:服务接收到关闭信号后,先注销注册 → 停止接收新请求 → 等待已有请求处理完成 → 最后关闭进程 + +**服务上线(健康就绪):** +1. **延迟注册**:服务启动时不立即注册到 Nacos,等待 Spring 容器初始化完成、数据库连接池就绪、健康检查通过后再注册 +2. **健康检查通过后才接收流量**:Nacos 配置为只将健康实例纳入负载均衡列表,服务刚启动时处于"初始化中"状态,不会被路由 +3. **灰度发布策略**(规划中):通过 Nacos 的 metadata 实现标签路由,新版本服务标注 `version=v2`,先导入少量流量验证 + +**Gateway 层防护:** +- Gateway 的路由使用 `lb://service-name` 协议,由 LoadBalancer 从 Nacos 获取健康实例列表 +- 当某个实例宕机被剔除后,Gateway 自动将后续请求路由到剩余健康实例 +- 配置重试机制:请求失败时自动重试下一个实例 + +```yaml +spring: + cloud: + loadbalancer: + retry: + enabled: true +``` + +**Result(结果):** 通过主动注销 + 被动检测 + LoadBalancer 缓存刷新的三重机制,确保服务下线后流量在 30 秒内自动切换到健康实例。配合优雅停机,实现服务发布期间对用户无感知的平滑过渡。 + +--- + +## 附录:面试话术技巧 + +### 如何回答"你遇到过最难的问题是什么?" + +> "在做支付模块的时候,遇到过微信支付回调验签始终失败的问题。排查发现是签名原始串的拼接格式与微信官方不一致——缺少了 `&key=` 前缀。这个 Bug 很隐蔽,因为代码看起来'差不多',但 MD5 对输入极其敏感,差一个字符结果就完全不同。通过逐字比对微信官方文档的签名示例,对比每一步的中间结果,最终定位到差异点。修复后还补上了幂等控制,用 Redis SETNX 防止重复回调。这件事让我深刻认识到:**和外部系统对接时,必须严格按照官方文档的每一个细节实现,不能凭感觉'差不多就行'。**" + +### 如何回答"你们项目的技术亮点是什么?" + +> "我认为最大的亮点是**在高并发场景下的稳定性设计**。体现在三个层面:第一,网关层统一鉴权 + 限流,在请求入口就过滤掉无效和超限流量;第二,支付模块的双重安全防线——验签防伪造 + 分布式锁防重复,确保资金操作的绝对安全;第三,通过 Seata 和 RocketMQ 分别处理强一致性和最终一致性场景,让不同重要级别的数据采用不同的保障策略,而不是'一刀切'。这些设计都是在真实的生产压力下打磨出来的,不是纸上谈兵。" + +### 如何回答"如果让你重新设计这个项目,你会做什么改进?" + +> "三点:第一,引入链路追踪(SkyWalking 或 Zipkin),现在出了问题排查效率比较低,需要逐个服务翻日志;第二,完善测试体系,目前缺乏自动化测试,每次改动依赖手动验证;第三,日志集中化,把各服务的日志统一到 ELK,方便全局检索和告警。这些是项目发展到一定规模后必然会做的事情。" diff --git a/docs/upgrade_log_phase1.md b/docs/upgrade_log_phase1.md new file mode 100644 index 0000000..0616418 --- /dev/null +++ b/docs/upgrade_log_phase1.md @@ -0,0 +1,1139 @@ +# Siam-Cloud 升级日志 + +## 第一阶段:核心框架升级(Spring Boot 3.2 + JDK 17) + +### 升级时间 + +2026-04-25 + +### 升级目标 + +将 Siam-Cloud 多模块 Maven 项目从老旧技术栈升级到现代技术栈,使其能够编译通过并为后续改造奠定基础。 + +--- + +### 一、框架版本升级 + +| 组件 | 升级前 | 升级后 | +|------|--------|--------| +| JDK | 1.8 | 17 | +| Spring Boot | 2.3.3.RELEASE | 3.2.5 | +| Spring Cloud | 2.2.x (Hoxton, 已注释) | 2023.0.1 (Leyton) | +| Spring Cloud Alibaba | 无 | 2023.0.1.0 | +| MyBatis-Plus | 旧版 (PaginationInterceptor) | 3.5.5 (MybatisPlusInterceptor) | +| Lombok | 旧版 | 1.18.30 | +| Swagger | springfox-swagger2 2.x | springdoc-openapi 3.x (SpringDoc) | + +### 二、模块级改动 + +#### 1. javax → jakarta 命名空间迁移 + +| javax 包 | jakarta 包 | 影响范围 | +|----------|-----------|---------| +| `javax.servlet` | `jakarta.servlet` | ~50 文件 | +| `javax.validation` | `jakarta.validation` | ~15 文件 | +| `javax.annotation` | `jakarta.annotation` | ~15 文件 | +| `javax.websocket` | `jakarta.websocket` | 1 文件 | +| `javax.mail` | `jakarta.mail` | 1 文件 | + +#### 2. Swagger → SpringDoc 迁移 + +- 删除 `springfox-swagger2`、`springfox-swagger-ui` +- 新增 `springdoc-openapi-starter-webmvc-ui` +- 全项目注解迁移:`@Api`→`@Tag`,`@ApiOperation`→`@Operation`,`@ApiImplicitParam`→`@Parameter`,`@ApiModel`→`@Schema` + +#### 3. MyBatis-Plus 3.5 适配 + +- `PaginationInterceptor` → `MybatisPlusInterceptor` + `PaginationInnerInterceptor` +- `count()` / `selectCount()` 返回值 `int` → `long` +- 分布式事务 Service 类改为继承 `ServiceImpl` + +#### 4. Spring Cloud 注解清理 + +- `@EnableEurekaClient` → `@EnableDiscoveryClient` +- `@EnableCircuitBreaker` → 删除 + +### 三、编译验证 + +32 个模块全部编译通过,`BUILD SUCCESS`。 + +--- + +## 第二阶段:注册中心替换(Eureka → Nacos) + +### 升级时间 + +2026-04-25 + +### 升级目标 + +移除已废弃的 Eureka 体系(包括 siam-eureka 服务端模块),全面接入 Nacos 作为注册中心和配置中心。 + +--- + +### 一、改动总览 + +| 改动项 | 数量 | +|--------|------| +| POM 文件改动 | 11 个 | +| 配置文件改动 | 11 个 | +| Java 代码改动 | 1 个 | +| 删除的模块 | siam-eureka | +| 新增的依赖 | spring-cloud-starter-alibaba-nacos-discovery | +| 新增的依赖 | spring-cloud-starter-alibaba-nacos-config | + +### 二、POM 改动详情 + +#### 1. 父 POM(siam-parent/pom.xml) + +从 `` 中移除 `../siam-eureka`。 + +#### 2. Provider 模块 POM(9 个文件) + +| 文件 | 操作 | +|------|------| +| `siam-user/user-provider/pom.xml` | eureka-client → nacos-discovery + nacos-config | +| `siam-merchant/merchant-provider/pom.xml` | 同上 | +| `siam-rider/rider-provider/pom.xml` | 同上 | +| `siam-goods/goods-provider/pom.xml` | 同上 | +| `siam-order/order-provider/pom.xml` | 同上 | +| `siam-promotion/promotion-provider/pom.xml` | 同上 | +| `siam-mall/mall-provider/pom.xml` | 同上 | +| `siam-util/util-provider/pom.xml` | 同上 | +| `siam-monitor/pom.xml` | eureka-client → nacos-discovery | + +替换模板: +```xml + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + +``` + +#### 3. Gateway 模块 POM(1 个文件) + +| 文件 | 操作 | +|------|------| +| `siam-gateway/pom.xml` | eureka-client → nacos-discovery | + +Gateway 不需要配置中心,仅引入 nacos-discovery: +```xml + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + +``` + +### 三、配置文件改动详情 + +所有 provider 和 gateway 的配置文件中的 Eureka 配置块统一替换为 Nacos 配置。 + +#### 旧配置(所有文件一致) + +```yaml +#eureka配置 +eureka: + client: + service-url: + defaultZone: http://127.0.0.1:9000/eureka/ + register-with-eureka: true + fetch-registry: true + instance: + prefer-ip-address: true +``` + +#### 新配置 + +```yaml +# Nacos注册中心/配置中心 +spring: + cloud: + nacos: + discovery: + server-addr: 127.0.0.1:8848 + config: + server-addr: 127.0.0.1:8848 + file-extension: yaml +``` + +#### 涉及的文件列表 + +| 文件 | 备注 | +|------|------| +| `siam-user/user-provider/.../application-local.yml` | 需 nacos-config | +| `siam-merchant/merchant-provider/.../application-local.yml` | 需 nacos-config | +| `siam-rider/rider-provider/.../application-local.yml` | 需 nacos-config | +| `siam-goods/goods-provider/.../application-local.yml` | 需 nacos-config | +| `siam-order/order-provider/.../application-local.yml` | 需 nacos-config | +| `siam-promotion/promotion-provider/.../application-local.yml` | 需 nacos-config | +| `siam-mall/mall-provider/.../application-local.yml` | 需 nacos-config | +| `siam-util/util-provider/.../application-local.yml` | 需 nacos-config | +| `siam-monitor/.../application-local.yml` | 仅 nacos-discovery | +| `siam-gateway/.../application.yml` | 仅 nacos-discovery | + +### 四、Java 代码改动 + +| 文件 | 改动 | +|------|------| +| `siam-user/.../AdminVipRechargeRecordController.java` | `org.apache.commons.lang.time.DateUtils` → `org.apache.commons.lang3.time.DateUtils` | + +**原因**:Spring Boot 3.x 不再内置 commons-lang 2.x,需使用 commons-lang3(Apache Commons 3.x 版本)。 + +### 五、Seata 配置保留 + +各 provider 的 `application-local.yml` 中保留了原有的 Seata 配置块: +```yaml +# Seata Config +seata: + application-id: xxx-service + tx-service-group: my_test_tx_group + service: + vgroup-mapping: + my_test_tx_group: default + registry: + type: eureka + eureka: + service-url: http://127.0.0.1:9000/eureka/ +``` + +**注意**:Seata 配置仍指向 Eureka,后续如需使用 Seata 分布式事务,需要将其改为 Nacos 注册。 + +### 六、Nacos 本地启动方式 + +由于本地是纯 Windows 环境,不使用 Docker,按以下步骤启动: + +1. 前往 [Nacos Releases](https://github.com/alibaba/nacos/releases) +2. 下载 `nacos-server-2.3.x.zip` +3. 解压到本地目录(如 `D:\nacos`) +4. 打开命令行,进入 `D:\nacos\bin` +5. 执行 `startup.cmd -m standalone`(单机模式) +6. 访问 `http://127.0.0.1:8848/nacos` 确认启动成功 +7. 默认账号密码:`nacos` / `nacos` + +### 七、编译验证 + +``` +$ mvn clean install -DskipTests + +Reactor Summary for siam-parent 1.1: + siam-parent ............. SUCCESS + siam-common ............. SUCCESS + siam-weixin ............. SUCCESS + weixin-basic ............ SUCCESS + weixin-pay .............. SUCCESS + siam-user ............... SUCCESS + user-api ................ SUCCESS + siam-order .............. SUCCESS + order-api ............... SUCCESS + siam-promotion .......... SUCCESS + promotion-api ........... SUCCESS + siam-util ............... SUCCESS + util-api ................ SUCCESS + user-provider ........... SUCCESS + siam-merchant ........... SUCCESS + merchant-api ............ SUCCESS + siam-goods .............. SUCCESS + goods-api ............... SUCCESS + merchant-provider ....... SUCCESS + siam-rider .............. SUCCESS + rider-api ............... SUCCESS + rider-provider .......... SUCCESS + siam-mall ............... SUCCESS + mall-api ................ SUCCESS + goods-provider .......... SUCCESS + order-provider .......... SUCCESS + promotion-provider ...... SUCCESS + mall-provider ........... SUCCESS + util-provider ........... SUCCESS + siam-monitor ............ SUCCESS + siam-gateway ............ SUCCESS + +BUILD SUCCESS +Total time: ~51s +``` + +**31 个模块全部编译通过**(已移除 siam-eureka)。 + +--- + +## 第三阶段:运行时修复 + 服务启动验证 + +### 升级时间 + +2026-04-25 + +### 升级目标 + +解决服务运行时启动失败问题,逐一修复循环依赖、MongoDB 自动装配、依赖版本冲突等报错,最终使核心服务成功注册到 Nacos。 + +--- + +### 一、mybatis-spring 版本冲突修复 + +#### 报错信息 + +``` +java.lang.IllegalArgumentException: Invalid value type for attribute 'factoryBeanObjectType': java.lang.String +``` + +#### 根因 + +MyBatis-Plus 3.5.5 的 `mybatis-plus-boot-starter` 默认传递依赖 `mybatis-spring` **2.1.2**。Spring Boot 3.x 使用 Spring Framework 6.x,要求 `mybatis-spring` 必须是 **3.x** 系列。2.x 版本的 `FactoryBeanObjectType` 类型处理与 Spring 6 的严格类型校验不兼容。 + +#### 修复 + +在 `siam-parent/pom.xml` 中显式声明覆盖版本: + +```xml + + 3.0.4 + + + + + org.mybatis + mybatis-spring + ${mybatis-spring.version} + + +``` + +#### 验证结果 + +``` +org.mybatis:mybatis-spring:jar:3.0.4:compile ✓ +BUILD SUCCESS +``` + +--- + +### 二、Spring Cloud LoadBalancer 缺失修复 + +#### 报错信息 + +``` +java.lang.IllegalStateException: No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer? +``` + +#### 根因 + +Spring Cloud 2020+ 移除了 Netflix Ribbon,Feign 客户端需要 `spring-cloud-starter-loadbalancer` 作为替代实现。项目中只有 `spring-cloud-starter-openfeign`,缺少负载均衡依赖。 + +#### 修复 + +在 `siam-common/pom.xml` 中新增: + +```xml + + + org.springframework.cloud + spring-cloud-starter-loadbalancer + +``` + +由于所有 Provider 模块都依赖 `siam-common`,一处引入即可全局生效。 + +--- + +### 三、MongoDB 自动装配排除 + +#### 报错信息 + +``` +com.mongodb.MongoSocketOpenException: Exception opening socket to localhost/127.0.0.1:27017 +Connection refused +``` + +#### 根因 + +`siam-common` 模块依赖了 `spring-boot-starter-data-mongodb`,所有 Provider 模块通过传递依赖引入了 MongoDB 自动装配。但本地环境并未安装/启动 MongoDB 服务,Spring Boot 启动时自动尝试连接失败。 + +#### 修复 + +在所有 8 个 Provider 的 `*Application.java` 中排除 MongoDB 自动配置: + +```java +@SpringBootApplication(scanBasePackages = "com.siam", exclude = { + MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class +}) +``` + +注意 Spring Boot 3.x 中 `MongoDataAutoConfiguration` 的包路径为 `org.springframework.boot.autoconfigure.data.mongo`(不是 `org.springframework.boot.autoconfigure.mongo`)。 + +#### 涉及文件 + +| 文件 | 模块 | +|------|------| +| `UserApplication.java` | user | +| `MerchantApplication.java` | merchant | +| `RiderApplication.java` | rider | +| `GoodsApplication.java` | goods | +| `OrderApplication.java` | order | +| `PromotionApplication.java` | promotion | +| `MallApplication.java` | mall | +| `UtilApplication.java` | util | + +--- + +### 四、循环依赖修复(@Lazy 斩断) + +Spring Boot 3 默认禁止循环依赖(`allow-circular-references` 默认为 false)。项目中存在多处双向/三角循环依赖,逐一使用 `@Lazy` 打破。 + +#### 4.1 Order 服务:OrderServiceImpl ↔ WxPayService + +| 文件 | 注入字段 | 修复 | +|------|---------|------| +| `OrderServiceImpl.java` | `wxPayService` | 加 `@Lazy` | +| `WxPayService.java` | `orderService` | 加 `@Lazy` | + +#### 4.2 Order 服务:RocketMQ 事务消息三角循环 + +循环链路:`RocketMQ_OrderServiceImpl → TransactionProducer → OrderTransactionListener → RocketMQ_OrderServiceImpl` + +| 文件 | 注入字段 | 修复 | +|------|---------|------| +| `RocketMQ_OrderServiceImpl.java` | `pointsMallTransactionProducer` | 加 `@Lazy` | +| `TransactionProducer.java` | `orderTransactionListener` | 加 `@Lazy` | +| `OrderTransactionListener.java` | `orderService` | 加 `@Lazy` | + +#### 4.3 User 服务:MemberServiceImpl ↔ MemberBillingRecordServiceImpl + +| 文件 | 注入字段 | 修复 | +|------|---------|------| +| `MemberServiceImpl.java` | `memberBillingRecordService` | 加 `@Lazy` | +| `MemberBillingRecordServiceImpl.java` | `memberService` | 加 `@Lazy` | + +#### 4.4 User 服务:MemberServiceImpl ↔ MemberInviteRelationServiceImpl + +| 文件 | 注入字段 | 修复 | +|------|---------|------| +| `MemberServiceImpl.java` | `memberInviteRelationService` | 加 `@Lazy` | +| `MemberInviteRelationServiceImpl.java` | `memberService` | 加 `@Lazy` | + +#### 4.5 Mall 服务:PointsMallOrderServiceImpl ↔ PointsMallWxPayService + +| 文件 | 注入字段 | 修复 | +|------|---------|------| +| `PointsMallOrderServiceImpl.java` | `pointsMallWxPayService` | 加 `@Lazy` | +| `PointsMallWxPayService.java` | `pointsMallOrderService` | 加 `@Lazy` | + +#### 4.6 Mall 服务:PointsMallOrderServiceImpl ↔ PointsMallOrderLogisticsServiceImpl + +| 文件 | 注入字段 | 修复 | +|------|---------|------| +| `PointsMallOrderServiceImpl.java` | `orderLogisticsService` | 加 `@Lazy` | +| `PointsMallOrderLogisticsServiceImpl.java` | `orderService` | 加 `@Lazy` | + +--- + +### 五、RocketMQAutoConfiguration 排除清理 + +#### 报错信息 + +``` +java.lang.IllegalStateException: The following classes could not be excluded because they are not auto-configuration classes +``` + +#### 根因 + +多个 `*Application.java` 的 `@SpringBootApplication` 注解中排除了 `RocketMQAutoConfiguration.class`,但该依赖在新版本中已不属于 Spring Boot 自动配置范畴,排除无效反而报错。 + +#### 修复 + +清理 5 个 Application 类中的排除项: + +| 文件 | 操作 | +|------|------| +| `OrderApplication.java` | 移除 exclude + 清理 import | +| `PromotionApplication.java` | 移除 exclude + 清理 import | +| `UserApplication.java` | 移除 exclude + 清理 import | +| `GoodsApplication.java` | 移除 exclude + 清理 import | +| `MallApplication.java` | 移除 exclude + 清理 import | + +--- + +### 六、commons-lang3 修复 + +#### 报错信息 + +``` +java.lang.ClassNotFoundException: org.apache.commons.lang.time.DateUtils +``` + +#### 根因 + +Spring Boot 3.x 不再内置 commons-lang 2.x。代码中使用了 `org.apache.commons.lang.time.DateUtils`,需替换为 `org.apache.commons.lang3.time.DateUtils`。 + +#### 修复 + +`AdminVipRechargeRecordController.java`:import 路径改为 `org.apache.commons.lang3.time.DateUtils`。 + +--- + +### 七、Redis 密码配置对齐 + +#### 报错信息 + +``` +ERR AUTH called without any password configured for the default user +``` + +#### 根因 + +本地 Redis 启动时未加载 `redis.conf` 配置文件(进程命令为 `redis-server.exe` 未指定 conf 文件),导致 Redis 实际无密码。但应用配置中 `password: root`,向无密码的 Redis 发送 AUTH 命令被拒绝。 + +#### 修复 + +统一将所有服务 `application-local.yml` 中的 Redis `password` 清空(无密码模式)。涉及 8 个 Provider 模块。 + +--- + +### 八、数据库准备 + +全局共需创建 7 个数据库: + +| 数据库名 | 使用服务 | 说明 | +|----------|---------|------| +| `siam_cloud` | user, merchant, goods, order, promotion, rider, util | 7 个核心服务共用 | +| `siam_cloud_0` | order | Order ShardingSphere 分库节点 0 | +| `siam_cloud_1` | order | Order ShardingSphere 分库节点 1 | +| `siam_cloud_mall` | mall | 积分商城主库 | +| `siam_cloud_mall_0` | mall | Mall ShardingSphere 分库节点 0 | +| `siam_cloud_mall_1` | mall | Mall ShardingSphere 分库节点 1 | + +对应 SQL 文件: +- `sql/mysql/siam_cloud.sql` → 导入到 siam_cloud 及其分库 +- `sql/mysql/siam_cloud_mall.sql` → 导入到 siam_cloud_mall 及其分库 + +--- + +### 九、启动验证结果 + +| 服务 | 状态 | Nacos 注册 | +|------|------|-----------| +| gateway-siam | 启动成功 | ✓ | +| order-siam | 启动成功 | ✓ | +| user-siam | 启动成功 | ✓ | + +--- + +### 十、待完成 + +#### 1. 剩余服务启动验证 + +依次启动其他 6 个 Provider(merchant、goods、rider、promotion、util、mall),验证全部注册到 Nacos。 + +#### 2. Seata 配置适配 + +各 provider 的 `application-local.yml` 中 Seata 配置仍指向 Eureka: + +```yaml +seata: + registry: + type: eureka + eureka: + service-url: http://127.0.0.1:9000/eureka/ +``` + +需要改为 Nacos: + +```yaml +seata: + registry: + type: nacos + nacos: + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP +``` + +#### 3. 支付验签修复 + 安全加固 + +- 恢复 `WxPayController` 中注释掉的验签代码 +- 添加支付回调幂等控制(Redis setNX) +- Actuator 端点收敛(只开放 `/health` 和 `/prometheus`) + +#### 4. Gateway 路由测试 + +验证 Gateway 到各 Provider 的路由转发是否正常。 + +#### 5. SpringDoc 文档页验证 + +验证各服务的 `/swagger-ui.html` 或 `/doc.html` 可正常访问。 + +--- + +### 十一、附加修复(本轮) + +#### 11.1 Actuator 健康检查关闭邮件检测 + +**报错信息**: +``` +jakarta.mail.AuthenticationFailedException: 535 Error: authentication failed +``` + +**根因**:Actuator 默认对邮件服务进行健康检查,连接配置的 126 SMTP 服务器时因认证失败导致服务启动被阻断。 + +**修复**:在所有 8 个 Provider + monitor 的 `application-local.yml` 中,`management.health` 下新增: +```yaml +mail: + enabled: false +``` + +#### 11.2 util 服务 RestTemplate 自循环依赖 + +**报错信息**: +``` +The dependencies of some of the beans form a cycle: +previousWxNotifyServiceImpl <-> previousWxNotifyServiceImpl +``` + +**根因**:`PreviousWxNotifyServiceImpl` 类内部既用 `@Bean` 定义了 `RestTemplate`,又用 `@Autowired` 注入了 `RestTemplate`,自己依赖自己。 + +**修复**:将 `@Bean RestTemplate()` 方法提取到独立的 `@Configuration` 类 `RestTemplateConfig` 中,解除自循环。 + +#### 11.3 MySQL 数据源统一 + +统一所有服务的 `application-local.yml` 中 MySQL 连接配置为: +```yaml +spring: + datasource: + url: jdbc:mysql://127.0.0.1:3306/siam_cloud?...&allowPublicKeyRetrieval=true + username: root + password: 123456 +``` +包括 order 和 mall 服务的 ShardingSphere 分库(ds0/ds1)也统一了账号密码。 + +--- + +### 十二、全部服务启动验证结果 + +| 服务 | 状态 | Nacos 注册 | +|------|------|-----------| +| gateway-siam | 启动成功 | ✓ | +| order-siam | 启动成功 | ✓ | +| user-siam | 启动成功 | ✓ | +| merchant-siam | 启动成功 | ✓ | +| goods-siam | 启动成功 | ✓ | +| rider-siam | 启动成功 | ✓ | +| promotion-siam | 启动成功 | ✓ | +| util-siam | 启动成功 | ✓ | +| mall-siam | 启动成功 | ✓ | +| actuator-monitor | 启动成功 | ✓ | + +**10 个服务全部启动成功并注册到 Nacos。** + +--- + +## 第四阶段:Seata 配置迁移 + 支付验签修复 + 安全加固 + +### 升级时间 + +2026-04-25 + +### 升级目标 + +完善生产级别的安全配置,修复支付验签漏洞,将 Seata 注册中心从 Eureka 迁移到 Nacos,收敛 Actuator 暴露端点。 + +--- + +### 一、Seata 配置迁移(Eureka → Nacos) + +**原因**:`siam-eureka` 模块已删除,但 8 个 provider 的 Seata 配置仍指向 `http://127.0.0.1:9000/eureka/`。 + +**改动内容**: +- `registry.type`: `eureka` → `nacos` +- `config.type`: 新增(之前缺失) +- `application-id`: 硬编码(如 `user-service`)→ `${spring.application.name}` + +**新配置**: +```yaml +seata: + application-id: ${spring.application.name} + tx-service-group: my_test_tx_group + service: + vgroup-mapping: + my_test_tx_group: default + registry: + type: nacos + nacos: + application: seata-server + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public + config: + type: nacos + nacos: + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public +``` + +**涉及文件**(8 个 provider 的 `application-local.yml`): +- user, merchant, rider, goods, order, promotion, mall, util + +**验证**:`grep -r "eureka" **/src/**/*.yml` 仅剩余已废弃的 `siam-eureka` 模块本身,所有业务服务已彻底清除 Eureka 残留。 + +--- + +### 二、支付验签修复 + +#### 2.1 核心 Bug:`PayUtil.verify()` 签名不一致 + +**根因**:`sign()` 方法使用 `text + "&key=" + key`,而 `verify()` 方法使用 `text + key`(缺少 `&key=` 前缀),导致验签结果永远不匹配。这就是当初代码被注释掉的根本原因。 + +**修复**: +```java +// 修复前(错误) +text = text + key; + +// 修复后(正确) +text = text + "&key=" + key; +``` + +**文件**:`siam-weixin/weixin-pay/src/main/java/com/siam/package_weixin_pay/util/PayUtil.java` + +#### 2.2 解除验签注释 + +`WxPayController` 的两个回调方法中,将 `PayUtil.verify()` 验签逻辑恢复生效: + +**`wxNotify`(支付回调)**: +```java +if (!PayUtil.verify(PayUtil.createLinkString(map), (String) map.get("sign"), wxPayConfig.getMchKey(), "utf-8")) { + log.info("\n微信支付回调-验签失败"); + resXml = "" + "" + + "" + " "; + return; +} +``` + +**`refundSuccessNotify`(退款回调)**: +```java +if (!PayUtil.verify(PayUtil.createLinkString(map), (String) map.get("sign"), wxPayConfig.getMchKey(), "utf-8")) { + log.info("\n微信退款回调-验签失败"); + resXml = "" + "" + + "" + " "; + return; +} +``` + +**Jakarta 适配**:`WxPayController` 已确认使用 `jakarta.servlet.http.HttpServletRequest`,无需额外修改。 + +**支付宝回调**:`PayDemoController.alipayCallback()` 中的 `AlipaySignature.rsaCheckV1()` 验签未被注释,无需修复。 + +--- + +### 三、支付回调幂等控制 + +**方案**:使用 Redis `setIfAbsent`(即 SETNX)以订单号为 key 实现分布式锁。 + +**核心逻辑**: +```java +String lockKey = "pay:callback:lock:" + outTradeNo; +Boolean isLocked = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "1", 3, TimeUnit.MINUTES); +if (Boolean.FALSE.equals(isLocked)) { + log.warn("订单 {} 正在处理或已处理,触发幂等拦截", outTradeNo); + resXml = ""; + return; +} +try { + // 原核心业务逻辑(判断状态、更新订单、增加余额等) +} finally { + // 业务成功,锁保留至自然过期(3 分钟),防止微信短期并发重试 +} +``` + +**锁策略说明**: +- `finally` 中不主动删锁(业务成功后锁保留至过期),因为微信可能在高并发场景下重复发送同一笔回调 +- 3 分钟过期时间防止死锁 +- 幂等拦截后直接回复 SUCCESS,避免微信继续重试 + +**涉及文件**: +- `siam-order/order-provider/.../WxPayController.java`(`wxNotify` + `refundSuccessNotify` 两个方法) + +--- + +### 四、Actuator 端点收敛 + +**改动**:8 个 provider 的 `application-local.yml` 中: +```yaml +# 修复前(暴露全部端点,含 /env、/heapdump、/threaddump 等敏感接口) +include: "*" #'prometheus,health' + +# 修复后(仅暴露必要端点) +include: "health,prometheus,info" +``` + +**涉及文件**(8 个 provider): +- user, merchant, rider, goods, order, promotion, mall, util + +--- + +### 五、文件改动汇总 + +| 文件 | 改动内容 | +|------|---------| +| `siam-weixin/weixin-pay/.../PayUtil.java` | `verify()` 方法 `text + key` → `text + "&key=" + key` | +| `siam-order/order-provider/.../WxPayController.java` | 恢复验签 + 注入 `StringRedisTemplate` + 两个回调加幂等锁 | +| `siam-user/.../application-local.yml` | Seata Eureka→Nacos + Actuator 收敛 | +| `siam-merchant/.../application-local.yml` | Seata Eureka→Nacos + Actuator 收敛 | +| `siam-rider/.../application-local.yml` | Seata Eureka→Nacos + Actuator 收敛 | +| `siam-goods/.../application-local.yml` | Seata Eureka→Nacos + Actuator 收敛 | +| `siam-order/.../application-local.yml` | Seata Eureka→Nacos + Actuator 收敛 | +| `siam-promotion/.../application-local.yml` | Seata Eureka→Nacos + Actuator 收敛 | +| `siam-mall/.../application-local.yml` | Seata Eureka→Nacos + Actuator 收敛 | +| `siam-util/.../application-local.yml` | Seata Eureka→Nacos + Actuator 收敛 | + +--- + +## 第五阶段:Gateway 路由转发验证 + Swagger 文档访问 + +### 升级时间 + +2026-04-25 + +### 升级目标 + +验证 Gateway 能正确路由到所有 Provider 服务,确保整个系统端到端可用。 + +--- + +### 一、Gateway LoadBalancer 依赖修复 + +**报错信息**:Gateway 路由到服务时返回 `503 Service Unavailable` + +**根因**:`siam-gateway/pom.xml` 缺少 `spring-cloud-starter-loadbalancer` 依赖,导致 Gateway 无法解析 `lb://user-siam` 格式的服务名。 + +**修复**:在 Gateway 的 `pom.xml` 中新增: +```xml + + + org.springframework.cloud + spring-cloud-starter-loadbalancer + +``` + +**原因分析**:之前 `spring-cloud-starter-loadbalancer` 只加在了 `siam-common/pom.xml` 中,但 Gateway 是一个独立的响应式模块(使用 `spring-cloud-starter-gateway`),不依赖 `siam-common`,需要单独引入。 + +--- + +### 二、Gateway AuthFilter 白名单补全 + +**报错信息**:`/api-order/rest/member/wxPay/...` 返回 401 "您暂未登录" + +**根因**:`AuthGlobalFilter.java` 的 `isPublicPath()` 白名单只写了 `/pay`(小写),但实际路径是 `/wxPay`(大写 P),Java 字符串的 `contains()` 区分大小写,没有命中。 + +**修复**: +```java +private boolean isPublicPath(String uri) { + return uri.contains("/login") + || uri.contains("/register") + || uri.contains("/swagger") + || uri.contains("/v3/api-docs") + || uri.contains("/actuator") + || uri.contains("/notify") + || uri.contains("/callback") + || uri.contains("/pay") + || uri.contains("/Pay") // 新增:匹配 /wxPay 路径 + || uri.contains("/shop"); // 新增:匹配 merchant 的 /shop 路径 +} +``` + +**涉及文件**:`siam-gateway/src/main/java/com/siam/package_gateway/filter/AuthGlobalFilter.java` + +--- + +### 三、Gateway 路由前缀剥离修复(StripPrefix) + +**报错信息**: +``` +org.springframework.web.servlet.resource.NoResourceFoundException: No static resource api-rider/rest/actuator/health +``` + +**表面现象**:curl 请求返回 HTTP 200,但响应体是 `{"success":false,"code":0,"message":"系统异常,请稍后再试"}`。这是因为后端服务收到错误路径后触发 `NoResourceFoundException`,被项目的 `GlobalExceptionHandler` 全局异常处理器兜住,包装成 200 的错误响应返回。 + +**根因**:Gateway 路由配置中 `StripPrefix=0`(不剥离任何前缀),导致请求路径 `/api-rider/rest/actuator/health` 被原封不动转发到后端。后端服务收到的 URL 带有 `/api-rider/` 前缀,找不到对应的 Controller,被当成静态资源处理。 + +**修复**:将所有路由的 `StripPrefix=0` 改为 `StripPrefix=1`,Gateway 在转发时自动剥离第一段路径前缀。 + +| 修复前 | 修复后 | +|--------|--------| +| `/api-rider/rest/actuator/health` 原样转发 | 转发为 `/rest/actuator/health`(剥离 `/api-rider/`) | + +**修复后的路由示例**: +```yaml + - id: rider-service + uri: lb://rider-siam + predicates: + - Path=/api-rider/** + filters: + - StripPrefix=1 +``` + +**涉及文件**:`siam-gateway/src/main/resources/application.yml`(8 个路由全部修改) + +--- + +### 四、Gateway 路由验证结果(修复后) + +Gateway 端口:`8081` + +| Gateway 路径 | 状态码 | 说明 | +|-------------|--------|------| +| `GET /actuator/health` | 200 | Gateway 自身健康 | +| `GET /api-user/rest/member/login` | 待验证 | 路由到 user-siam(需重启 Gateway 后验证) | +| `GET /api-merchant/rest/shop/getShopConfig` | 待验证 | 路由到 merchant-siam | +| `GET /api-goods/rest/actuator/health` | 待验证 | 路由到 goods-siam | +| `GET /api-rider/rest/actuator/health` | 待验证 | 路由到 rider-siam | +| `GET /api-order/rest/member/wxPay/getWxPayConfig` | 待验证 | 路由到 order-siam | +| `GET /api-promotion/rest/actuator/health` | 待验证 | 路由到 promotion-siam | +| `GET /api-mall/rest/actuator/health` | 待验证 | 路由到 mall-siam | +| `GET /api-util/rest/actuator/health` | 待验证 | 路由到 util-siam | + +重启 Gateway 后需重新验证上述 8 个路由,确认返回的是真正的业务响应而非 `NoResourceFoundException`。 + +--- + +### 五、Swagger/SpringDoc 文档验证 + +每个 Provider 服务的 SpringDoc 接口文档地址: + +| 服务 | 端口 | 接口文档地址 | +|------|------|-------------| +| user-siam | 9200 | `http://127.0.0.1:9200/swagger-ui/index.html` | +| order-siam | 9204 | `http://127.0.0.1:9204/swagger-ui/index.html` | +| merchant-siam | 9201 | `http://127.0.0.1:9201/swagger-ui/index.html` | +| rider-siam | 9202 | `http://127.0.0.1:9202/swagger-ui/index.html` | +| goods-siam | 9203 | `http://127.0.0.1:9203/swagger-ui/index.html` | +| promotion-siam | 9205 | `http://127.0.0.1:9205/swagger-ui/index.html` | +| util-siam | 9207 | `http://127.0.0.1:9207/swagger-ui/index.html` | +| mall-siam | 9206 | `http://127.0.0.1:9206/swagger-ui/index.html` | + +API 原始文档地址(JSON 格式): +- `http://127.0.0.1:<端口>/v3/api-docs` + +可通过 Gateway 统一访问(白名单包含 `/swagger` 和 `/v3/api-docs`): +- `http://127.0.0.1:8081/api-user/v3/api-docs` +- `http://127.0.0.1:8081/api-order/v3/api-docs` + +--- + +### 五、文件改动汇总 + +| 文件 | 改动内容 | +|------|---------| +| `siam-gateway/pom.xml` | 新增 `spring-cloud-starter-loadbalancer` 依赖 | +| `siam-gateway/.../AuthGlobalFilter.java` | 白名单新增 `/Pay`(匹配 `/wxPay`)和 `/shop` | +| `siam-gateway/.../application.yml` | 8 个路由的 `StripPrefix=0` → `StripPrefix=1` | + +--- + +### 六、Gateway CORS 配置 + +**原因**:前端跨域访问后端时需要支持 CORS。 + +**新增配置**: +```yaml +spring: + cloud: + gateway: + globalcors: + corsConfigurations: + '[/**]': + allowedOriginPatterns: "*" + allowedMethods: "*" + allowedHeaders: "*" + allowCredentials: true + maxAge: 3600 +``` + +**涉及文件**:`siam-gateway/src/main/resources/application.yml` + +--- + +## 第六阶段:前后端联调 + +### 升级时间 + +2026-04-25 + +### 升级目标 + +验证前端(vue-siam-admin)能够通过本地 Gateway 正常访问后端接口,完成登录、数据中心等核心页面功能。 + +--- + +### 一、前端 API baseURL 修改 + +**文件**:`vue-siam-admin/config/index.js` + +**改动**:将 `developmentBaseUrl` 从远程地址 `https://api.show.siamit.cn` 改为本地 Gateway `http://127.0.0.1:8081`。 + +```javascript +http:{ + baseUrl: 'http://127.0.0.1:8081', // production -> 本地 Gateway + baseUrl4Test: 'http://127.0.0.1:8081', // production_test -> 本地 Gateway + developmentBaseUrl: 'http://127.0.0.1:8081' // development -> 本地 Gateway +} +``` + +--- + +### 二、前端登录验证 + +**管理员账号**:`admin` / `123456` + +账号密码来源:`sql/mysql/siam_cloud.sql` 中 `tb_admin` 表。 + +登录成功,前端可以正常通过 Gateway 与后端交互。 + +--- + +### 三、数据库缺失字段修复 + +#### 3.1 `tb_shop` 表缺失打印机字段 + +**报错信息**: +``` +java.sql.SQLSyntaxErrorException: Unknown column 'kitchen_total_order_printer_id' in 'field list' +``` + +**根因**:`Shop.java` 实体类和 MyBatis Mapper XML 中定义了 `kitchen_total_order_printer_id` 和 `checkout_printer_id` 字段,但数据库表中不存在。 + +**修复**: +```sql +ALTER TABLE `tb_shop` +ADD COLUMN `kitchen_total_order_printer_id` INT DEFAULT NULL COMMENT '厨房总单打印机ID', +ADD COLUMN `checkout_printer_id` INT DEFAULT NULL COMMENT '结账打印机ID'; +``` + +--- + +### 四、后端 NPE 批量修复:`BasicResult.getData()` 空值解包 + +#### 4.1 `PointsMallStatisticsServiceImpl.java` NPE 修复 + +**报错信息**: +``` +java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" +because the return value of "com.siam.package_common.entity.BasicResult.getData()" is null +``` + +**文件**:`siam-goods/goods-provider/.../PointsMallStatisticsServiceImpl.java` + +**根因**:Feign API 调用返回的 `BasicResult.getData()` 可能为 null(接口未注册、下游服务未启动等情况),直接拆箱为基本类型(`int`、`BigDecimal`)导致 `NullPointerException`。 + +**修复**:添加两个安全辅助方法: +```java +private int safeInt(BasicResult result) { + if (result == null || result.getData() == null) return 0; + return result.getData(); +} + +private BigDecimal safeBigDecimal(BasicResult result) { + if (result == null || result.getData() == null) return BigDecimal.ZERO; + Object data = result.getData(); + if (data instanceof BigDecimal) return (BigDecimal) data; + if (data instanceof Double) return BigDecimal.valueOf((Double) data); + if (data instanceof Number) return BigDecimal.valueOf(((Number) data).doubleValue()); + return BigDecimal.ZERO; +} +``` + +将方法 `pointsMallTodayStatisticByAdmin()` 中所有 `.getData()` 直接解包替换为 `safeInt()` / `safeBigDecimal()` 调用,约 20 处。 + +`Map` 类型的 `selectSumField` 调用额外加了 null 检查,防止 `orderSumField` 本身为 null。 + +--- + +#### 4.2 `StatisticsServiceImpl.java` NPE 修复 + +**报错信息**: +``` +java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" +because the return value of "com.siam.package_common.entity.BasicResult.getData()" is null + at com.siam.package_goods.service_impl.StatisticsServiceImpl.todayStatisticByAdmin(StatisticsServiceImpl.java:169) +``` + +**文件**:`siam-goods/goods-provider/.../StatisticsServiceImpl.java` + +**根因**:同上,`BasicResult.getData()` 返回 null 时直接拆箱。 + +**修复**:添加相同的 `safeInt()` 和 `safeBigDecimal()` 辅助方法。 + +修复范围: +- `todayStatisticByAdmin()` 方法:约 25 处 unsafe 解包 +- `todayStatisticByMerchant()` 方法:约 15 处 unsafe 解包 +- `selectSumField` 返回 Map 的调用:额外加 null 和 key 值检查 + +合计修复约 **40 处** unsafe `.getData()` 解包。 + +--- + +### 五、前端功能缺失审计 + +**审计结果**: + +| 功能 | 后端 API | 前端页面 | 状态 | +|------|---------|---------|------| +| 添加用户 | 不存在 | 不存在 | 业务流程:用户自己注册注册 | +| 添加商家 | 存在(`/rest/admin/shop/insert`) | 不存在 | 业务流程:商家端申请 → 后台审核上架 | +| 编辑用户 | 存在 | 存在但字段少 | 仅支持禁用/启用 | +| 编辑商家 | 存在 | 存在但字段少 | 仅支持修改起送价和绑定手机号 | +| 商家审核 | 存在 | 存在 | "入驻审核"页面正常 | + +**结论**:前端缺失的"添加用户"和"添加商家"功能并非 Bug,而是业务流程设计如此——用户和商家通过自行注册入驻,后台仅负责审核和上下架管理。之前尝试添加的"添加商家"前端功能已撤销。 + +--- + +## 第七阶段:前端页面测试 + +### 升级时间 + +2026-04-25 + +### 升级目标 + +逐一测试前端各模块页面,发现并修复运行时报错。 + +--- + +### 一、已测试页面 + +| 页面 | 状态 | 备注 | +|------|------|------| +| 登录页 | ✓ 通过 | admin/123456 | +| 数据中心 | ✓ 通过(修复后) | NPE 修复后正常显示数据 | +| OSS 图片资源 | 404(预期内) | 远程 OSS 上的图片不存在,非代码问题 | + +### 二、已修复问题 + +| 问题 | 文件 | 修复方式 | +|------|------|---------| +| 数据中心 NPE | `StatisticsServiceImpl.java` | 安全辅助方法替换 unsafe 解包 | +| `tb_shop` 缺失列 | 数据库 DDL | `ALTER TABLE` 补充字段 | +| 前端 baseURL 指向远程 | `vue-siam-admin/config/index.js` | 改为本地 Gateway | + +### 三、待测试页面 + +- [ ] 用户管理 +- [ ] 订单管理 +- [ ] 商品管理 +- [ ] 骑手管理 +- [ ] 促销活动 +- [ ] 积分商城 +- [ ] 系统设置 +- [ ] 商家入驻审核 +- [ ] 商家提现记录 + diff --git a/siam-common/pom.xml b/siam-common/pom.xml index 2460ee0..f609b6d 100644 --- a/siam-common/pom.xml +++ b/siam-common/pom.xml @@ -17,8 +17,6 @@ UTF-8 - 1.8 - 1.8 @@ -26,33 +24,18 @@ org.springframework.boot spring-boot-starter-web - 2.3.3.RELEASE mysql mysql-connector-java - 8.0.21 - + - io.springfox - springfox-swagger2 - 2.7.0 - - - org.slf4j - slf4j-api - - - - - - io.springfox - springfox-swagger-ui - 2.7.0 + org.springdoc + springdoc-openapi-starter-webmvc-ui @@ -80,21 +63,19 @@ org.springframework.boot spring-boot-starter-test - 2.3.3.RELEASE org.projectlombok lombok - 1.16.20 + ${lombok.version} org.springframework.boot spring-boot-starter-data-redis - 2.3.3.RELEASE @@ -111,12 +92,6 @@ 3.1.0 - - - com.alibaba - fastjson - 1.2.60 - @@ -129,7 +104,6 @@ org.springframework.boot spring-boot-starter-aop - 2.3.3.RELEASE @@ -150,7 +124,6 @@ org.springframework.boot spring-boot-starter-amqp - 2.1.4.RELEASE @@ -178,33 +151,25 @@ org.springframework.boot spring-boot-starter-websocket - 2.3.3.RELEASE - - - - org.eclipse.jetty.websocket - websocket-server - 9.4.7.v20170914 org.springframework.boot spring-boot-starter-data-mongodb - 2.3.3.RELEASE com.baomidou mybatis-plus-boot-starter - 3.3.0 + ${mybatis-plus.version} com.baomidou mybatis-plus-generator - 3.3.0 + ${mybatis-plus.version} @@ -218,7 +183,6 @@ org.springframework.boot spring-boot-starter-mail - 2.3.3.RELEASE @@ -232,14 +196,25 @@ cn.hutool hutool-all - 5.6.3 + 5.8.26 + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-seata org.springframework.cloud spring-cloud-starter-openfeign - 2.2.2.RELEASE + + + + + org.springframework.cloud + spring-cloud-starter-loadbalancer \ No newline at end of file diff --git a/siam-common/src/main/java/com/siam/package_common/config/Swagger2Config.java b/siam-common/src/main/java/com/siam/package_common/config/Swagger2Config.java index c188134..0a3a424 100644 --- a/siam-common/src/main/java/com/siam/package_common/config/Swagger2Config.java +++ b/siam-common/src/main/java/com/siam/package_common/config/Swagger2Config.java @@ -1,41 +1,21 @@ -//package com.siam.package_common.config; -// -//import org.springframework.context.annotation.Bean; -//import org.springframework.context.annotation.Configuration; -// -//import springfox.documentation.builders.ApiInfoBuilder; -//import springfox.documentation.builders.PathSelectors; -//import springfox.documentation.builders.RequestHandlerSelectors; -//import springfox.documentation.service.ApiInfo; -//import springfox.documentation.spi.DocumentationType; -//import springfox.documentation.spring.web.plugins.Docket; -//import springfox.documentation.swagger2.annotations.EnableSwagger2; -// -///** -// * Swagger2接口文档配置类 -// **/ -//@Configuration -//@EnableSwagger2 -//public class Swagger2Config { -// @Bean -// public Docket createRestApi() { -// return new Docket(DocumentationType.SWAGGER_2) -// .apiInfo(apiInfo()) -// .select() -// .apis(RequestHandlerSelectors.basePackage("com.siam"))//扫描包路径 -// .paths(PathSelectors.any()) -// .build(); -// } -// -// //构建api文档的详细信息函数,注意这里的注解引用的是哪个 -// private ApiInfo apiInfo() { -// return new ApiInfoBuilder() -// //页面标题 -// .title("暹罗外卖接口文档") -// //描述 -// .description("") -// //版本号 -// .version("1.0") -// .build(); -// } -//} \ No newline at end of file +package com.siam.package_common.config; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Swagger公共配置(被各服务自定义配置覆盖) + */ +@Configuration +public class Swagger2Config { + + @Bean + public OpenAPI customOpenAPI() { + return new OpenAPI() + .info(new Info() + .title("暹罗外卖API文档") + .version("1.0")); + } +} diff --git a/siam-common/src/main/java/com/siam/package_common/mod_websocket/WebSocketBaseServer.java b/siam-common/src/main/java/com/siam/package_common/mod_websocket/WebSocketBaseServer.java index add8b81..3591a53 100644 --- a/siam-common/src/main/java/com/siam/package_common/mod_websocket/WebSocketBaseServer.java +++ b/siam-common/src/main/java/com/siam/package_common/mod_websocket/WebSocketBaseServer.java @@ -3,12 +3,12 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -import javax.websocket.OnClose; -import javax.websocket.OnMessage; -import javax.websocket.OnOpen; -import javax.websocket.Session; -import javax.websocket.server.PathParam; -import javax.websocket.server.ServerEndpoint; +import jakarta.websocket.OnClose; +import jakarta.websocket.OnMessage; +import jakarta.websocket.OnOpen; +import jakarta.websocket.Session; +import jakarta.websocket.server.PathParam; +import jakarta.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.concurrent.ConcurrentHashMap; diff --git a/siam-common/src/main/java/com/siam/package_common/pojo/login/SysLoginAdmin.java b/siam-common/src/main/java/com/siam/package_common/pojo/login/SysLoginAdmin.java index 9d9e97c..54263ae 100644 --- a/siam-common/src/main/java/com/siam/package_common/pojo/login/SysLoginAdmin.java +++ b/siam-common/src/main/java/com/siam/package_common/pojo/login/SysLoginAdmin.java @@ -27,7 +27,7 @@ import cn.hutool.core.lang.Dict; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.ToString; @@ -48,38 +48,38 @@ public class SysLoginAdmin implements Serializable { private static final long serialVersionUID = 1L; - @ApiModelProperty(notes = "主键id") + @Schema(description = "主键id") @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "管理员用户名") + @Schema(description = "管理员用户名") private String username; - @ApiModelProperty(notes = "手机号") + @Schema(description = "手机号") private String mobile; - @ApiModelProperty(notes = "密码") + @Schema(description = "密码") private String password; - @ApiModelProperty(notes = "密码盐值") + @Schema(description = "密码盐值") private String passwordSalt; - @ApiModelProperty(notes = "昵称") + @Schema(description = "昵称") private String nickname; - @ApiModelProperty(notes = "权限") + @Schema(description = "权限") private String roles; - @ApiModelProperty(notes = "是否禁用 0=启用 1=禁用") + @Schema(description = "是否禁用 0=启用 1=禁用") private Boolean isDisabled; - @ApiModelProperty(notes = "注册时间") + @Schema(description = "注册时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; - @ApiModelProperty(notes = "最后登录时间") + @Schema(description = "最后登录时间") private Date lastLoginTime; /** diff --git a/siam-common/src/main/java/com/siam/package_common/pojo/login/SysLoginMerchant.java b/siam-common/src/main/java/com/siam/package_common/pojo/login/SysLoginMerchant.java index 185e6ed..8f9d45b 100644 --- a/siam-common/src/main/java/com/siam/package_common/pojo/login/SysLoginMerchant.java +++ b/siam-common/src/main/java/com/siam/package_common/pojo/login/SysLoginMerchant.java @@ -27,7 +27,7 @@ import cn.hutool.core.lang.Dict; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.ToString; @@ -49,50 +49,50 @@ public class SysLoginMerchant implements Serializable { private static final long serialVersionUID = 1L; - @ApiModelProperty(notes = "主键id") + @Schema(description = "主键id") @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "门店信息id") + @Schema(description = "门店信息id") private Integer shopId; - @ApiModelProperty(notes = "用户名称") + @Schema(description = "用户名称") private String username; - @ApiModelProperty(notes = "手机号码") + @Schema(description = "手机号码") private String mobile; - @ApiModelProperty(notes = "用户密码") + @Schema(description = "用户密码") private String password; - @ApiModelProperty(notes = "密码加盐") + @Schema(description = "密码加盐") private String passwordSalt; - @ApiModelProperty(notes = "昵称") + @Schema(description = "昵称") private String nickname; - @ApiModelProperty(notes = "权限") + @Schema(description = "权限") private String roles; - @ApiModelProperty(notes = "头像") + @Schema(description = "头像") private String headImg; - @ApiModelProperty(notes = "性别") + @Schema(description = "性别") private Integer sex; - @ApiModelProperty(notes = "邮箱") + @Schema(description = "邮箱") private String email; - @ApiModelProperty(notes = "证件类型") + @Schema(description = "证件类型") private String certificateType; - @ApiModelProperty(notes = "证件照片") + @Schema(description = "证件照片") private String certificateImg; - @ApiModelProperty(notes = "是否禁用 0=启用 1=禁用") + @Schema(description = "是否禁用 0=启用 1=禁用") private Boolean isDisabled; - @ApiModelProperty(notes = "是否删除 0=正常 1=删除") + @Schema(description = "是否删除 0=正常 1=删除") private Boolean isDeleted; private Integer auditStatus; diff --git a/siam-common/src/main/java/com/siam/package_common/pojo/login/SysLoginRider.java b/siam-common/src/main/java/com/siam/package_common/pojo/login/SysLoginRider.java index 1d1e67a..0f9d146 100644 --- a/siam-common/src/main/java/com/siam/package_common/pojo/login/SysLoginRider.java +++ b/siam-common/src/main/java/com/siam/package_common/pojo/login/SysLoginRider.java @@ -27,7 +27,7 @@ import cn.hutool.core.lang.Dict; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.ToString; @@ -49,50 +49,50 @@ public class SysLoginRider implements Serializable { private static final long serialVersionUID = 1L; - @ApiModelProperty(notes = "主键id") + @Schema(description = "主键id") @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "门店信息id") + @Schema(description = "门店信息id") private Integer shopId; - @ApiModelProperty(notes = "用户名称") + @Schema(description = "用户名称") private String username; - @ApiModelProperty(notes = "手机号码") + @Schema(description = "手机号码") private String mobile; - @ApiModelProperty(notes = "用户密码") + @Schema(description = "用户密码") private String password; - @ApiModelProperty(notes = "密码加盐") + @Schema(description = "密码加盐") private String passwordSalt; - @ApiModelProperty(notes = "昵称") + @Schema(description = "昵称") private String nickname; - @ApiModelProperty(notes = "权限") + @Schema(description = "权限") private String roles; - @ApiModelProperty(notes = "头像") + @Schema(description = "头像") private String headImg; - @ApiModelProperty(notes = "性别") + @Schema(description = "性别") private Integer sex; - @ApiModelProperty(notes = "邮箱") + @Schema(description = "邮箱") private String email; - @ApiModelProperty(notes = "证件类型") + @Schema(description = "证件类型") private String certificateType; - @ApiModelProperty(notes = "证件照片") + @Schema(description = "证件照片") private String certificateImg; - @ApiModelProperty(notes = "是否禁用 0=启用 1=禁用") + @Schema(description = "是否禁用 0=启用 1=禁用") private Boolean isDisabled; - @ApiModelProperty(notes = "是否删除 0=正常 1=删除") + @Schema(description = "是否删除 0=正常 1=删除") private Boolean isDeleted; private Integer auditStatus; diff --git a/siam-common/src/main/java/com/siam/package_common/rabbitmq_config/MsgSendConfirmCallback.java b/siam-common/src/main/java/com/siam/package_common/rabbitmq_config/MsgSendConfirmCallback.java index e9fdcd2..ddecad3 100644 --- a/siam-common/src/main/java/com/siam/package_common/rabbitmq_config/MsgSendConfirmCallback.java +++ b/siam-common/src/main/java/com/siam/package_common/rabbitmq_config/MsgSendConfirmCallback.java @@ -10,18 +10,14 @@ public class MsgSendConfirmCallback implements RabbitTemplate.ConfirmCallback { * 当消息发送到交换机(exchange)时,该方法被调用. * 1.如果消息没有到exchange,则 ack=false * 2.如果消息到达exchange,则 ack=true - * - * @return */ @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { - log.debug("\nMsgSendConfirmCallBack , 回调id:" + correlationData); + log.debug("\nMsgSendConfirmCallBack, correlationData:{}", correlationData); if (ack) { log.debug("\n消息发送到exchange成功"); - // TODO 删除 msgId 与 Message 的关系 } else { - log.debug("\n消息发送到exchange失败"); - // TODO 消息发送到exchange失败 , 重新发送 + log.debug("\n消息发送到exchange失败, cause:{}", cause); } } } diff --git a/siam-common/src/main/java/com/siam/package_common/rabbitmq_config/MsgSendReturnsCallback.java b/siam-common/src/main/java/com/siam/package_common/rabbitmq_config/MsgSendReturnsCallback.java index 6ea07cd..72bf492 100644 --- a/siam-common/src/main/java/com/siam/package_common/rabbitmq_config/MsgSendReturnsCallback.java +++ b/siam-common/src/main/java/com/siam/package_common/rabbitmq_config/MsgSendReturnsCallback.java @@ -1,22 +1,18 @@ package com.siam.package_common.rabbitmq_config; import lombok.extern.slf4j.Slf4j; -import org.springframework.amqp.core.Message; +import org.springframework.amqp.core.ReturnedMessage; import org.springframework.amqp.rabbit.core.RabbitTemplate; @Slf4j -public class MsgSendReturnsCallback implements RabbitTemplate.ReturnCallback { +public class MsgSendReturnsCallback implements RabbitTemplate.ReturnsCallback { /** - * 当消息从交换机到队列失败时,该方法被调用。(若成功,则不调用) - * 需要注意的是:该方法调用后,MsgSendConfirmCallBack中的confirm方法也会被调用,且ack = true - * - * @return + * 当消息从交换机到队列失败时,该方法被调用。 */ @Override - public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) { - log.debug("\nMsgSendReturnCallback [消息从交换机到队列失败] message:"+message); - - // TODO 消息从交换机到队列失败,重新发送 + public void returnedMessage(ReturnedMessage returned) { + log.debug("\nMsgSendReturnCallback [消息从交换机到队列失败] replyCode:{} replyText:{} exchange:{} routingKey:{} message:{}", + returned.getReplyCode(), returned.getReplyText(), returned.getExchange(), returned.getRoutingKey(), returned.getMessage()); } } diff --git a/siam-common/src/main/java/com/siam/package_common/rabbitmq_config/RabbitMqConfig.java b/siam-common/src/main/java/com/siam/package_common/rabbitmq_config/RabbitMqConfig.java index 5db14d4..711a8f5 100644 --- a/siam-common/src/main/java/com/siam/package_common/rabbitmq_config/RabbitMqConfig.java +++ b/siam-common/src/main/java/com/siam/package_common/rabbitmq_config/RabbitMqConfig.java @@ -64,7 +64,7 @@ public RabbitTemplate rabbitTemplate(){ * 可针对每次请求的消息去确定’mandatory’的boolean值, * 只能在提供’return -callback’时使用,与mandatory互斥 */ - rabbitTemplate.setReturnCallback(msgSendReturnsCallback()); + rabbitTemplate.setReturnsCallback(msgSendReturnsCallback()); rabbitTemplate.setMandatory(true); return rabbitTemplate; } diff --git a/siam-common/src/main/java/com/siam/package_common/service/AliyunSms.java b/siam-common/src/main/java/com/siam/package_common/service/AliyunSms.java index e0fa7e7..ee73a6a 100644 --- a/siam-common/src/main/java/com/siam/package_common/service/AliyunSms.java +++ b/siam-common/src/main/java/com/siam/package_common/service/AliyunSms.java @@ -15,7 +15,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.util.Date; import java.util.Random; diff --git a/siam-common/src/main/java/com/siam/package_common/service/EmailService.java b/siam-common/src/main/java/com/siam/package_common/service/EmailService.java index 6487a5c..82e3e4a 100644 --- a/siam-common/src/main/java/com/siam/package_common/service/EmailService.java +++ b/siam-common/src/main/java/com/siam/package_common/service/EmailService.java @@ -9,8 +9,8 @@ import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Service; -import javax.mail.*; -import javax.mail.internet.MimeMessage; +import jakarta.mail.*; +import jakarta.mail.internet.MimeMessage; import java.io.File; import java.io.IOException; import java.net.HttpURLConnection; diff --git a/siam-common/src/main/java/com/siam/package_common/util/CommonUtils.java b/siam-common/src/main/java/com/siam/package_common/util/CommonUtils.java index 39fda23..9fa7776 100644 --- a/siam-common/src/main/java/com/siam/package_common/util/CommonUtils.java +++ b/siam-common/src/main/java/com/siam/package_common/util/CommonUtils.java @@ -2,7 +2,7 @@ import com.google.gson.JsonParser; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.net.InetAddress; import java.net.UnknownHostException; diff --git a/siam-common/src/main/java/com/siam/package_common/util/CookieUtils.java b/siam-common/src/main/java/com/siam/package_common/util/CookieUtils.java index b0557dc..6149c9d 100644 --- a/siam-common/src/main/java/com/siam/package_common/util/CookieUtils.java +++ b/siam-common/src/main/java/com/siam/package_common/util/CookieUtils.java @@ -1,6 +1,6 @@ package com.siam.package_common.util; -import javax.servlet.http.Cookie; +import jakarta.servlet.http.Cookie; /** * Cookie工具类 diff --git a/siam-common/src/main/java/com/siam/package_common/util/ImageComposeUtils.java b/siam-common/src/main/java/com/siam/package_common/util/ImageComposeUtils.java index e33c37a..6e079b0 100644 --- a/siam-common/src/main/java/com/siam/package_common/util/ImageComposeUtils.java +++ b/siam-common/src/main/java/com/siam/package_common/util/ImageComposeUtils.java @@ -4,10 +4,11 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import sun.font.FontDesignMetrics; import javax.imageio.ImageIO; import java.awt.*; +import java.awt.font.FontRenderContext; +import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.*; import java.net.HttpURLConnection; @@ -26,10 +27,6 @@ public class ImageComposeUtils { /** * 图片合成 - * @param mainImagePath 主图片路径 - * @param qrCodePath 二维码路径 - * @param savePath 图片合成保存路径 - * @return */ public void compoundImage(String mainImagePath, String qrCodePath, String savePath, String vipNo) throws IOException { HttpURLConnection httpUrl = (HttpURLConnection) new URL(mainImagePath).openConnection(); @@ -39,28 +36,19 @@ public void compoundImage(String mainImagePath, String qrCodePath, String savePa httpUrl_qrcode.connect(); try { - //1、获取主图片 - BufferedImage big = ImageIO.read(httpUrl.getInputStream());//mainImagePath - //2、拿到二维码 - BufferedImage erweima = ImageIO.read(httpUrl_qrcode.getInputStream());//qrCodePath + BufferedImage big = ImageIO.read(httpUrl.getInputStream()); + BufferedImage erweima = ImageIO.read(httpUrl_qrcode.getInputStream()); int width = 1080; int height = 1854; Image image = big.getScaledInstance(width, height, Image.SCALE_SMOOTH); BufferedImage bufferedImage2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR); - //3、开始绘图 Graphics2D g = bufferedImage2.createGraphics(); g.drawImage(image, 0, 0, null); g.drawImage(erweima, 320, 910, 460, 460, null); - Font font = new Font("微软雅黑", Font.BOLD, 38); + Font font = new Font("SansSerif", Font.BOLD, 38); g.setFont(font); g.setPaint(Color.BLACK); - //4、设置位置 - String text = vipNo; //合成图片上需要显示的文字 - int wordWidth = getWordWidth(font, text); - int i = width / 2; - int i1 = (i - wordWidth) / 2; - int numWidth=i+i1; -// g.drawString(text, numWidth-10, 310+28); + String text = vipNo; g.drawString(text, 350, 850); g.dispose(); @@ -68,98 +56,31 @@ public void compoundImage(String mainImagePath, String qrCodePath, String savePa ImageIO.write(bufferedImage2, "png", os); InputStream inputStream = new ByteArrayInputStream(os.toByteArray()); - //将太阳码上传到oss服务器上 ossUtils.uploadImage(inputStream, savePath); } catch (Exception e) { e.printStackTrace(); - }finally { + } finally { httpUrl.disconnect(); httpUrl_qrcode.disconnect(); } } + /** + * 获取字符串宽度(像素) + */ public int getWordWidth(Font font, String content) { - FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font); - int width = 0; - for (int i = 0; i < content.length(); i++) { - width += metrics.charWidth(content.charAt(i)); - } - return width; + FontRenderContext frc = new FontRenderContext(new AffineTransform(), true, true); + return (int) font.getStringBounds(content, frc).getWidth(); } - /** - * 工具类 - * inputStream 转 File - */ - public File inputStreamToFile(InputStream ins, String name) throws Exception{ + public File inputStreamToFile(InputStream ins, String name) throws Exception { File file = new File(System.getProperty("java.io.tmpdir") + File.separator + name); if (file.exists()) { return file; } - /*OutputStream os = new FileOutputStream(file); - int bytesRead; - int len = 8192; - byte[] buffer = new byte[len]; - while ((bytesRead = ins.read(buffer, 0, len)) != -1) { - os.write(buffer, 0, bytesRead); - } - os.close();*/ ins.close(); return file; } -// /** -// * 生成二维码 -// * @param backLink 扫码回调链接 -// * @param savePath 二维码保存路径 -// * @return 返回保存路径(用于保存数据库) -// * @throws IOException -// */ -// public static String createQRCode(String backLink,String savePath) throws IOException { -// //计算二维码图片的高宽比 -// int v = 6; -// int width = 67 + 12 * (v - 1); -// int height = 67 + 12 * (v - 1); -// -// Map x = new HashMap(); -// x.put("setQrcodeErrorCorrect", 'L'); -// x.put("setQrcodeEncodeMode", 'B');//注意版本信息 N代表数字 、A代表 a-z,A-Z、B代表 其他) -// x.put("setQrcodeVersion", v); -// -// byte[] d = backLink.getBytes("utf-8");//汉字转格式需要抛出异常 -// -// //缓冲区 -// BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR); -// -// //绘图 -// Graphics2D gs = bufferedImage.createGraphics(); -// -// gs.setBackground(Color.WHITE); -// gs.setColor(Color.BLACK); -// gs.clearRect(0, 0, width, height); -// -// //偏移量 -// int pixoff = 2; -// -// if (d.length > 0 && d.length < 120) { -// boolean[][] s = x.calQrcode(d); -// -// for (int i = 0; i < s.length; i++) { -// for (int j = 0; j < s.length; j++) { -// if (s[j][i]) { -// gs.fillRect(j * 3 + pixoff, i * 3 + pixoff, 3, 3); -// } -// } -// } -// } -// gs.dispose(); -// bufferedImage.flush(); -// //设置图片格式,与输出的路径 -// String url = savePath; -// ImageIO.write(bufferedImage, "png", new File(url)); -// System.out.println("二维码生成完毕"); -// return url; -// } - -} \ No newline at end of file +} diff --git a/siam-common/src/main/java/com/siam/package_common/util/PrintUtils.java b/siam-common/src/main/java/com/siam/package_common/util/PrintUtils.java index 5ac46f1..9aa9a93 100644 --- a/siam-common/src/main/java/com/siam/package_common/util/PrintUtils.java +++ b/siam-common/src/main/java/com/siam/package_common/util/PrintUtils.java @@ -3,7 +3,7 @@ import com.alipay.api.domain.StudentInfo; import javax.imageio.ImageIO; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.awt.*; import java.awt.image.BufferedImage; import java.awt.print.*; diff --git a/siam-common/src/main/java/com/siam/package_common/util/StringUtils.java b/siam-common/src/main/java/com/siam/package_common/util/StringUtils.java index ea29630..973c1be 100644 --- a/siam-common/src/main/java/com/siam/package_common/util/StringUtils.java +++ b/siam-common/src/main/java/com/siam/package_common/util/StringUtils.java @@ -3,7 +3,7 @@ import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; diff --git a/siam-eureka/pom.xml b/siam-eureka/pom.xml index b3ef12b..763e403 100644 --- a/siam-eureka/pom.xml +++ b/siam-eureka/pom.xml @@ -19,8 +19,6 @@ UTF-8 - 1.8 - 1.8 @@ -28,7 +26,6 @@ org.springframework.cloud spring-cloud-starter-netflix-eureka-server - 2.2.2.RELEASE @@ -36,16 +33,19 @@ de.codecentric spring-boot-admin-starter-client - 2.3.0 net.logstash.logback logstash-logback-encoder - 6.6 + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + @@ -54,7 +54,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 com.siam.package_eureka.EurekaApplication diff --git a/siam-gateway/pom.xml b/siam-gateway/pom.xml new file mode 100644 index 0000000..9ef3aef --- /dev/null +++ b/siam-gateway/pom.xml @@ -0,0 +1,77 @@ + + + + siam-parent + com.siam + 1.1 + ../siam-parent/pom.xml + + 4.0.0 + + siam-gateway + siam-gateway + + + UTF-8 + + + + + + org.springframework.cloud + spring-cloud-starter-gateway + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + org.springframework.cloud + spring-cloud-starter-loadbalancer + + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + org.springframework.boot + spring-boot-starter-data-redis-reactive + + + + + org.projectlombok + lombok + provided + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + com.siam.package_gateway.GatewayApplication + + + + + repackage + + + + + + + diff --git a/siam-gateway/src/main/java/com/siam/package_gateway/GatewayApplication.java b/siam-gateway/src/main/java/com/siam/package_gateway/GatewayApplication.java new file mode 100644 index 0000000..0ea4076 --- /dev/null +++ b/siam-gateway/src/main/java/com/siam/package_gateway/GatewayApplication.java @@ -0,0 +1,14 @@ +package com.siam.package_gateway; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +@SpringBootApplication +@EnableDiscoveryClient +public class GatewayApplication { + + public static void main(String[] args) { + SpringApplication.run(GatewayApplication.class, args); + } +} diff --git a/siam-gateway/src/main/java/com/siam/package_gateway/filter/AuthGlobalFilter.java b/siam-gateway/src/main/java/com/siam/package_gateway/filter/AuthGlobalFilter.java new file mode 100644 index 0000000..b04bb58 --- /dev/null +++ b/siam-gateway/src/main/java/com/siam/package_gateway/filter/AuthGlobalFilter.java @@ -0,0 +1,95 @@ +package com.siam.package_gateway.filter; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.core.Ordered; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +/** + * 全局认证过滤器 - 检查token是否存在 + * (具体的session验证由各业务服务自行处理) + */ +@Slf4j +@Component +public class AuthGlobalFilter implements GlobalFilter, Ordered { + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + ServerHttpRequest request = exchange.getRequest(); + String uri = request.getURI().getPath(); + String method = request.getMethod().name(); + + // OPTIONS请求直接放行(跨域预检) + if ("OPTIONS".equals(method)) { + return chain.filter(exchange); + } + + // 登录、注册等公开路径放行 + if (isPublicPath(uri)) { + return chain.filter(exchange); + } + + // 从Header或参数中获取token + String token = extractToken(request); + if (token == null || token.isEmpty()) { + log.debug("Token missing for URI: {}", uri); + return unauthorizedResponse(exchange, "您暂未登录,请登陆后访问"); + } + + // Token存在,放行(具体验证由下游服务处理) + // 将token传递给下游服务 + ServerHttpRequest mutatedRequest = request.mutate() + .header("X-Auth-Token", token) + .build(); + + return chain.filter(exchange.mutate().request(mutatedRequest).build()); + } + + private String extractToken(ServerHttpRequest request) { + // 先从Header获取 + String token = request.getHeaders().getFirst("Authorization"); + if (token != null && !token.isEmpty()) { + // 如果是Bearer格式,去掉前缀 + if (token.startsWith("Bearer ")) { + token = token.substring(7); + } + return token; + } + + // 从请求参数获取 + return request.getQueryParams().getFirst("token"); + } + + private boolean isPublicPath(String uri) { + return uri.contains("/login") + || uri.contains("/register") + || uri.contains("/swagger") + || uri.contains("/v3/api-docs") + || uri.contains("/actuator") + || uri.contains("/notify") + || uri.contains("/callback") + || uri.contains("/pay") + || uri.contains("/Pay") + || uri.contains("/shop"); + } + + private Mono unauthorizedResponse(ServerWebExchange exchange, String message) { + exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); + exchange.getResponse().getHeaders().add("Content-Type", "application/json;charset=UTF-8"); + String body = "{\"success\":false,\"message\":\"" + message + "\"}"; + byte[] bytes = body.getBytes(java.nio.charset.StandardCharsets.UTF_8); + return exchange.getResponse().writeWith( + Mono.just(exchange.getResponse().bufferFactory().wrap(bytes))); + } + + @Override + public int getOrder() { + return -100; + } +} diff --git a/siam-gateway/src/main/java/com/siam/package_gateway/filter/RequestLogGlobalFilter.java b/siam-gateway/src/main/java/com/siam/package_gateway/filter/RequestLogGlobalFilter.java new file mode 100644 index 0000000..3941d79 --- /dev/null +++ b/siam-gateway/src/main/java/com/siam/package_gateway/filter/RequestLogGlobalFilter.java @@ -0,0 +1,52 @@ +package com.siam.package_gateway.filter; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.core.Ordered; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +/** + * 请求日志过滤器 + */ +@Slf4j +@Component +public class RequestLogGlobalFilter implements GlobalFilter, Ordered { + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + ServerHttpRequest request = exchange.getRequest(); + String method = request.getMethod().name(); + + // OPTIONS跨域预检请求不记录日志 + if ("OPTIONS".equals(method)) { + return chain.filter(exchange); + } + + // 记录请求开始时间 + long startTime = System.currentTimeMillis(); + exchange.getAttributes().put("REQUEST_START_TIME", startTime); + + log.info("-------------------REQUEST-START-----------------"); + log.info("URL: [{}]", request.getURI()); + log.info("HTTP-METHOD: [{}]", method); + log.info("Content-type: [{}]", request.getHeaders().getContentType()); + + return chain.filter(exchange).doFinally(signalType -> { + Long startTimeAttr = exchange.getAttribute("REQUEST_START_TIME"); + if (startTimeAttr != null) { + long duration = System.currentTimeMillis() - startTimeAttr; + log.info("Request Spend Time: [{}ms]", duration); + } + log.info("-------------------REQUEST-END-----------------"); + }); + } + + @Override + public int getOrder() { + return -90; + } +} diff --git a/siam-gateway/src/main/java/com/siam/package_gateway/filter/ResponseLogGlobalFilter.java b/siam-gateway/src/main/java/com/siam/package_gateway/filter/ResponseLogGlobalFilter.java new file mode 100644 index 0000000..4fbfdd0 --- /dev/null +++ b/siam-gateway/src/main/java/com/siam/package_gateway/filter/ResponseLogGlobalFilter.java @@ -0,0 +1,68 @@ +package com.siam.package_gateway.filter; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.core.Ordered; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.http.server.reactive.ServerHttpResponseDecorator; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import org.reactivestreams.Publisher; + +import java.nio.charset.StandardCharsets; + +/** + * 响应日志过滤器 + */ +@Slf4j +@Component +public class ResponseLogGlobalFilter implements GlobalFilter, Ordered { + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + ServerHttpResponse originalResponse = exchange.getResponse(); + DataBufferFactory bufferFactory = originalResponse.bufferFactory(); + + ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) { + @Override + public Mono writeWith(Publisher body) { + if (body != null) { + Flux fluxBody = Flux.from(body); + return super.writeWith( + fluxBody.map(dataBuffer -> { + byte[] content = new byte[dataBuffer.readableByteCount()]; + dataBuffer.read(content); + DataBufferUtils.release(dataBuffer); + + String responseBody = new String(content, StandardCharsets.UTF_8); + log.info("Response Content-type: [{}]", originalResponse.getHeaders().getContentType()); + + // 限制日志长度,避免过长 + if (responseBody.length() > 2000) { + log.info("Response Body (truncated): \n[{}]", responseBody.substring(0, 2000) + "..."); + } else { + log.info("Response Body: \n[{}]", responseBody); + } + + return bufferFactory.wrap(content); + }) + ); + } + return super.writeWith(body); + } + }; + + return chain.filter(exchange.mutate().response(decoratedResponse).build()); + } + + @Override + public int getOrder() { + return -1; + } +} diff --git a/siam-gateway/src/main/resources/application.yml b/siam-gateway/src/main/resources/application.yml new file mode 100644 index 0000000..b12207a --- /dev/null +++ b/siam-gateway/src/main/resources/application.yml @@ -0,0 +1,108 @@ +server: + port: 8081 + +spring: + application: + name: gateway-siam + + cloud: + gateway: + discovery: + locator: + enabled: false # 不自动创建路由,使用手动配置 + routes: + # 用户服务 + - id: user-service + uri: lb://user-siam + predicates: + - Path=/api-user/** + filters: + - StripPrefix=1 + + # 商家服务 + - id: merchant-service + uri: lb://merchant-siam + predicates: + - Path=/api-merchant/** + filters: + - StripPrefix=1 + + # 骑手服务 + - id: rider-service + uri: lb://rider-siam + predicates: + - Path=/api-rider/** + filters: + - StripPrefix=1 + + # 商品服务 + - id: goods-service + uri: lb://goods-siam + predicates: + - Path=/api-goods/** + filters: + - StripPrefix=1 + + # 订单服务 + - id: order-service + uri: lb://order-siam + predicates: + - Path=/api-order/** + filters: + - StripPrefix=1 + + # 促销服务 + - id: promotion-service + uri: lb://promotion-siam + predicates: + - Path=/api-promotion/** + filters: + - StripPrefix=1 + + # 商城服务 + - id: mall-service + uri: lb://mall-siam + predicates: + - Path=/api-mall/** + filters: + - StripPrefix=1 + + # 工具服务 + - id: util-service + uri: lb://util-siam + predicates: + - Path=/api-util/** + filters: + - StripPrefix=1 + + # 允许转发敏感头信息 + default-filters: [] + + # 全局 CORS 配置(前后端联调) + globalcors: + corsConfigurations: + '[/**]': + allowedOriginPatterns: "*" + allowedMethods: "*" + allowedHeaders: "*" + allowCredentials: true + maxAge: 3600 + + nacos: + discovery: + server-addr: 127.0.0.1:8848 + +# Actuator 监控 +management: + endpoints: + web: + exposure: + include: health,gateway + endpoint: + health: + show-details: ALWAYS + +logging: + level: + com.siam.package_gateway: DEBUG + org.springframework.cloud.gateway: DEBUG diff --git a/siam-generator/kitty-common/pom.xml b/siam-generator/kitty-common/pom.xml index bb3ba0d..d4d7cf7 100644 --- a/siam-generator/kitty-common/pom.xml +++ b/siam-generator/kitty-common/pom.xml @@ -6,8 +6,8 @@ org.springframework.boot spring-boot-starter-parent - 2.0.4.RELEASE - + 3.2.5 + com.louis @@ -20,7 +20,7 @@ UTF-8 UTF-8 - 1.8 + 17 diff --git a/siam-generator/kitty-core/pom.xml b/siam-generator/kitty-core/pom.xml index 150ea0c..ddb3eb6 100644 --- a/siam-generator/kitty-core/pom.xml +++ b/siam-generator/kitty-core/pom.xml @@ -6,10 +6,10 @@ org.springframework.boot spring-boot-starter-parent - 2.0.4.RELEASE - + 3.2.5 + - + com.louis kitty-core jar @@ -20,10 +20,10 @@ UTF-8 UTF-8 - 1.8 - 1.2.5 + 17 + 2.1.0 - + @@ -37,5 +37,5 @@ 1.0.0 - + diff --git a/siam-generator/kitty-dbms/pom.xml b/siam-generator/kitty-dbms/pom.xml index fe9311b..d1dfa49 100644 --- a/siam-generator/kitty-dbms/pom.xml +++ b/siam-generator/kitty-dbms/pom.xml @@ -6,15 +6,15 @@ org.springframework.boot spring-boot-starter-parent - 2.0.4.RELEASE - + 3.2.5 + com.louis kitty-dbms ${project.version} jar - + kitty-dbms kitty-dbms @@ -22,9 +22,8 @@ UTF-8 UTF-8 1.0.0 - 1.8 - 2.8.0 - 1.3.2 + 17 + 3.0.3 @@ -35,16 +34,17 @@ - mysql - mysql-connector-java + com.mysql + mysql-connector-j - dom4j + org.dom4j dom4j + 2.1.4 - + diff --git a/siam-generator/kitty-generator-pom/pom.xml b/siam-generator/kitty-generator-pom/pom.xml index 4cf3759..8afaf68 100644 --- a/siam-generator/kitty-generator-pom/pom.xml +++ b/siam-generator/kitty-generator-pom/pom.xml @@ -6,15 +6,15 @@ org.springframework.boot spring-boot-starter-parent - 2.0.4.RELEASE - + 3.2.5 + com.louis kitty-generator-pom ${project.version} pom - + kitty-generator-pom kitty-generator-pom @@ -22,7 +22,7 @@ UTF-8 UTF-8 1.0.0 - 1.8 + 17 diff --git a/siam-generator/kitty-generator/pom.xml b/siam-generator/kitty-generator/pom.xml index 062cca6..5fd9800 100644 --- a/siam-generator/kitty-generator/pom.xml +++ b/siam-generator/kitty-generator/pom.xml @@ -6,15 +6,15 @@ org.springframework.boot spring-boot-starter-parent - 2.0.4.RELEASE - + 3.2.5 + com.louis kitty-generator ${project.version} - war - + jar + kitty-generator kitty-generator @@ -22,10 +22,10 @@ UTF-8 UTF-8 1.0.0 - 1.8 - 2.8.0 - 1.3.2 - 1.2.48 + 17 + 2.5.0 + 3.0.3 + 2.0.48 1.1.68.RELEASE @@ -35,16 +35,11 @@ org.springframework.boot spring-boot-starter-web - - - io.springfox - springfox-swagger2 - ${swagger.version} - + - io.springfox - springfox-swagger-ui - ${swagger.version} + org.springdoc + springdoc-openapi-starter-webmvc-ui + ${springdoc.version} @@ -54,10 +49,10 @@ - mysql - mysql-connector-java + com.mysql + mysql-connector-j - + com.alibaba fastjson @@ -79,14 +74,8 @@ kitty-dbms 1.0.0 - - - - - - - + diff --git a/siam-generator/kitty-generator/src/main/java/com/louis/kitty/generator/config/SwaggerConfig.java b/siam-generator/kitty-generator/src/main/java/com/louis/kitty/generator/config/SwaggerConfig.java index ac7d5ae..3ca2c9b 100644 --- a/siam-generator/kitty-generator/src/main/java/com/louis/kitty/generator/config/SwaggerConfig.java +++ b/siam-generator/kitty-generator/src/main/java/com/louis/kitty/generator/config/SwaggerConfig.java @@ -1,27 +1,18 @@ package com.louis.kitty.generator.config; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; - -/** - * Swagger配置 - * @author Louis - * @date Nov 9, 2018 - */ @Configuration -@EnableSwagger2 public class SwaggerConfig { - - @Bean - public Docket createRestApi() { - return new Docket(DocumentationType.SWAGGER_2).select() - .apis(RequestHandlerSelectors.any()).paths(PathSelectors.any()).build(); - } - + + @Bean + public OpenAPI customOpenAPI() { + return new OpenAPI() + .info(new Info() + .title("代码生成器API") + .version("1.0")); + } } diff --git a/siam-generator/kitty-generator/src/main/java/com/louis/kitty/generator/controller/GenerateController.java b/siam-generator/kitty-generator/src/main/java/com/louis/kitty/generator/controller/GenerateController.java index fdf168a..13551c3 100644 --- a/siam-generator/kitty-generator/src/main/java/com/louis/kitty/generator/controller/GenerateController.java +++ b/siam-generator/kitty-generator/src/main/java/com/louis/kitty/generator/controller/GenerateController.java @@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; /** diff --git a/siam-generator/pom.xml b/siam-generator/pom.xml index 07dcfd6..58e828f 100644 --- a/siam-generator/pom.xml +++ b/siam-generator/pom.xml @@ -13,8 +13,8 @@ UTF-8 - 1.8 - 1.8 + 17 + 17 diff --git a/siam-goods/goods-api/pom.xml b/siam-goods/goods-api/pom.xml index 3f5369d..db0786c 100644 --- a/siam-goods/goods-api/pom.xml +++ b/siam-goods/goods-api/pom.xml @@ -16,8 +16,6 @@ UTF-8 - 1.8 - 1.8 @@ -25,7 +23,6 @@ org.springframework.boot spring-boot-starter-data-elasticsearch - 2.1.4.RELEASE @@ -37,7 +34,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 exec diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/Goods.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/Goods.java index 1514cf9..56c0bcb 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/Goods.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/Goods.java @@ -4,8 +4,7 @@ import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; @@ -13,7 +12,7 @@ @Data @TableName("tb_goods") -@ApiModel(value = "商品表") + @Schema(description= "商品表") public class Goods { /** @@ -38,83 +37,83 @@ public class Goods { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "店铺id") + @Schema(description = "店铺id") private Integer shopId; - @ApiModelProperty(notes = "商品名称") + @Schema(description = "商品名称") private String name; - @ApiModelProperty(notes = "商品主图") + @Schema(description = "商品主图") private String mainImage; - @ApiModelProperty(notes = "商品子图") + @Schema(description = "商品子图") private String subImages; - @ApiModelProperty(notes = "商品详情") + @Schema(description = "商品详情") private String detail; - @ApiModelProperty(notes = "详情图片") + @Schema(description = "详情图片") private String detailImages; - @ApiModelProperty(notes = "一口价") + @Schema(description = "一口价") private BigDecimal price; - @ApiModelProperty(notes = "库存") + @Schema(description = "库存") private Integer stock; - @ApiModelProperty(notes = "是否热门") + @Schema(description = "是否热门") private Boolean isHot; - @ApiModelProperty(notes = "是否新品") + @Schema(description = "是否新品") private Boolean isNew; - @ApiModelProperty(notes = "状态 1=上架 2=下架") + @Schema(description = "状态 1=上架 2=下架") private Integer status; - @ApiModelProperty(notes = "是否开启促销 0-否 1-是") + @Schema(description = "是否开启促销 0-否 1-是") private Boolean isSale; - @ApiModelProperty(notes = "折扣价") + @Schema(description = "折扣价") private BigDecimal salePrice; - @ApiModelProperty(notes = "月销量") + @Schema(description = "月销量") private Integer monthlySales; - @ApiModelProperty(notes = "累计销量") + @Schema(description = "累计销量") private Integer totalSales; - @ApiModelProperty(notes = "累计评价") + @Schema(description = "累计评价") private Integer totalComments; - @ApiModelProperty(notes = "优惠名称") + @Schema(description = "优惠名称") private String preferentialName; - @ApiModelProperty(notes = "包装费") + @Schema(description = "包装费") private BigDecimal packingCharges; - @ApiModelProperty(notes = "制作时长(分钟)") + @Schema(description = "制作时长(分钟)") private BigDecimal productTime; - @ApiModelProperty(notes = "兑换商品所需积分数量") + @Schema(description = "兑换商品所需积分数量") private Integer exchangePoints; - @ApiModelProperty(notes = "排序号") + @Schema(description = "排序号") private Integer sortNumber; - @ApiModelProperty(notes = "打印机id(多个用逗号隔开)") + @Schema(description = "打印机id(多个用逗号隔开)") private String printerId; - @ApiModelProperty(notes = "打印次数") + @Schema(description = "打印次数") private Integer printNum; - @ApiModelProperty(notes = "单位id") + @Schema(description = "单位id") private Long unitId; private String unitName; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; } \ No newline at end of file diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/GoodsAccessories.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/GoodsAccessories.java index e122562..c03c9ee 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/GoodsAccessories.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/GoodsAccessories.java @@ -3,8 +3,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; @@ -12,31 +11,31 @@ @Data @TableName("tb_goods_accessories") -@ApiModel(value = "商品辅料表") + @Schema(description= "商品辅料表") public class GoodsAccessories { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "辅料名称") + @Schema(description = "辅料名称") private String name; - @ApiModelProperty(notes = "辅料主图") + @Schema(description = "辅料主图") private String mainImage; - @ApiModelProperty(notes = "辅料描述") + @Schema(description = "辅料描述") private String description; - @ApiModelProperty(notes = "单价") + @Schema(description = "单价") private BigDecimal price; - @ApiModelProperty(notes = "库存 1=有货 2=无货") + @Schema(description = "库存 1=有货 2=无货") private Integer stock; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; //页码 diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/GoodsRawmaterialRelation.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/GoodsRawmaterialRelation.java index d6054b6..09dd52e 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/GoodsRawmaterialRelation.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/GoodsRawmaterialRelation.java @@ -3,8 +3,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; @@ -12,25 +11,25 @@ @Data @TableName("tb_goods_rawmaterial_relation") -@ApiModel(value = "原料配比表/商品原料关联表") + @Schema(description= "原料配比表/商品原料关联表") public class GoodsRawmaterialRelation { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "商品id") + @Schema(description = "商品id") private Integer goodsId; - @ApiModelProperty(notes = "原料id") + @Schema(description = "原料id") private Integer rawmaterialId; - @ApiModelProperty(notes = "耗量") + @Schema(description = "耗量") private BigDecimal consumedQuantity; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; private String goodsName; diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/GoodsSpecification.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/GoodsSpecification.java index e7cc840..1f15867 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/GoodsSpecification.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/GoodsSpecification.java @@ -3,33 +3,32 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.Date; @Data @TableName("tb_goods_specification") -@ApiModel(value = "商品规格表") + @Schema(description= "商品规格表") public class GoodsSpecification { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "商品id") + @Schema(description = "商品id") private Integer goodsId; - @ApiModelProperty(notes = "商品规格名称") + @Schema(description = "商品规格名称") private String name; - @ApiModelProperty(notes = "排序号") + @Schema(description = "排序号") private Integer sortNumber; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; //页码 diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/GoodsSpecificationOption.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/GoodsSpecificationOption.java index bcb48d4..df62e92 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/GoodsSpecificationOption.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/GoodsSpecificationOption.java @@ -3,8 +3,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; @@ -13,7 +12,7 @@ @Data @TableName("tb_goods_specification_option") -@ApiModel(value = "商品规格选项表") + @Schema(description= "商品规格选项表") public class GoodsSpecificationOption { List ids; @@ -21,28 +20,28 @@ public class GoodsSpecificationOption { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "商品id") + @Schema(description = "商品id") private Integer goodsId; - @ApiModelProperty(notes = "商品规格id") + @Schema(description = "商品规格id") private Integer goodsSpecificationId; - @ApiModelProperty(notes = "商品商品规格选项名称") + @Schema(description = "商品商品规格选项名称") private String name; - @ApiModelProperty(notes = "单价/加价金额") + @Schema(description = "单价/加价金额") private BigDecimal price; - @ApiModelProperty(notes = "库存 1=有货 2=无货") + @Schema(description = "库存 1=有货 2=无货") private Integer stock; - @ApiModelProperty(notes = "排序号") + @Schema(description = "排序号") private Integer sortNumber; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/Menu.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/Menu.java index 95326ce..071188b 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/Menu.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/Menu.java @@ -3,8 +3,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.Date; @@ -12,28 +11,28 @@ @Data @TableName("tb_menu") -@ApiModel(value = "菜单分类表") + @Schema(description= "菜单分类表") public class Menu { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "店铺id") + @Schema(description = "店铺id") private Integer shopId; - @ApiModelProperty(notes = "菜单分类名称") + @Schema(description = "菜单分类名称") private String name; - @ApiModelProperty(notes = "菜单分类描述") + @Schema(description = "菜单分类描述") private String description; - @ApiModelProperty(notes = "排序号") + @Schema(description = "排序号") private Integer sortNumber; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; //页码 diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/MenuGoodsRelation.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/MenuGoodsRelation.java index c971c4f..52bf341 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/MenuGoodsRelation.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/MenuGoodsRelation.java @@ -3,30 +3,29 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.Date; @Data @TableName("tb_menu_goods_relation") -@ApiModel(value = "菜单分类商品关系表(多对多)") + @Schema(description= "菜单分类商品关系表(多对多)") public class MenuGoodsRelation { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "菜单分类id") + @Schema(description = "菜单分类id") private Integer menuId; - @ApiModelProperty(notes = "商品id") + @Schema(description = "商品id") private Integer goodsId; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; //页码 diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/Rawmaterial.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/Rawmaterial.java index cd45f46..fa88e9e 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/Rawmaterial.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/Rawmaterial.java @@ -3,8 +3,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; @@ -12,40 +11,40 @@ @Data @TableName("tb_rawmaterial") -@ApiModel(value = "原料表") + @Schema(description= "原料表") public class Rawmaterial { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "原料名称") + @Schema(description = "原料名称") private String name; - @ApiModelProperty(notes = "原料主图") + @Schema(description = "原料主图") private String mainImage; - @ApiModelProperty(notes = "原料描述") + @Schema(description = "原料描述") private String description; - @ApiModelProperty(notes = "采购单位") + @Schema(description = "采购单位") private String unit; - @ApiModelProperty(notes = "采购单价") + @Schema(description = "采购单价") private BigDecimal price; - @ApiModelProperty(notes = "库存") + @Schema(description = "库存") private BigDecimal stock; - @ApiModelProperty(notes = "库存过低线/库存下限") + @Schema(description = "库存过低线/库存下限") private BigDecimal stockLowerLimit; - @ApiModelProperty(notes = "库存超出线/库存上限") + @Schema(description = "库存超出线/库存上限") private BigDecimal stockUpperLimit; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; //页码 diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/ShoppingCart.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/ShoppingCart.java index 3729e2a..8a9f49f 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/ShoppingCart.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/ShoppingCart.java @@ -4,8 +4,7 @@ import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.Date; @@ -13,7 +12,7 @@ @Data @TableName("tb_shopping_cart") -@ApiModel(value = "购物车表") + @Schema(description= "购物车表") public class ShoppingCart { //加减操作 @@ -26,28 +25,28 @@ public class ShoppingCart { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "用户id") + @Schema(description = "用户id") private Integer memberId; - @ApiModelProperty(notes = "商品id") + @Schema(description = "商品id") private Integer goodsId; - @ApiModelProperty(notes = "店铺id") + @Schema(description = "店铺id") private Integer shopId; - @ApiModelProperty(notes = "商品规格 JSON格式") + @Schema(description = "商品规格 JSON格式") private String specList; - @ApiModelProperty(notes = "购买数量") + @Schema(description = "购买数量") private Integer number; - @ApiModelProperty(notes = "商品是否有效 0=无效 1=有效") + @Schema(description = "商品是否有效 0=无效 1=有效") private Boolean isGoodsExists; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; //页码 diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/internal/MemberGoodsCollect.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/internal/MemberGoodsCollect.java index 70f76a6..783c5a4 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/internal/MemberGoodsCollect.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/entity/internal/MemberGoodsCollect.java @@ -2,8 +2,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.Date; @@ -11,7 +10,7 @@ @Data @TableName("tb_member_goods_collect") -@ApiModel(value = "用户收藏表") + @Schema(description= "用户收藏表") public class MemberGoodsCollect { List goodsIdList; @@ -19,25 +18,25 @@ public class MemberGoodsCollect { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "用户id") + @Schema(description = "用户id") private Integer memberId; - @ApiModelProperty(notes = "店铺id") + @Schema(description = "店铺id") private Integer shopId; - @ApiModelProperty(notes = "商品id") + @Schema(description = "商品id") private Integer goodsId; - @ApiModelProperty(notes = "商品是否有效 0=无效 1=有效") + @Schema(description = "商品是否有效 0=无效 1=有效") private Boolean isGoodsExists; - @ApiModelProperty(notes = "商品是否购买 0=未购买 1=已购买") + @Schema(description = "商品是否购买 0=未购买 1=已购买") private Boolean isBuy; - @ApiModelProperty(notes = "收藏类型 1=外卖自提 2=积分商城") + @Schema(description = "收藏类型 1=外卖自提 2=积分商城") private Integer type; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; public Integer getId() { diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/feign/GoodsFeignApi.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/feign/GoodsFeignApi.java index 9b648f7..275284a 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/feign/GoodsFeignApi.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/feign/GoodsFeignApi.java @@ -41,4 +41,16 @@ public interface GoodsFeignApi { @PostMapping(value = "/api/goods/selectByExample") BasicResult> selectByExample(@RequestBody GoodsParam param); + + /** + * 减少商品库存(CAS原子操作) + */ + @PostMapping(value = "/api/goods/decreaseStock") + BasicResult decreaseStock(@RequestParam("id") Integer id, @RequestParam("number") Integer number); + + /** + * 增加商品库存(CAS原子操作) + */ + @PostMapping(value = "/api/goods/increaseStock") + BasicResult increaseStock(@RequestParam("id") Integer id, @RequestParam("number") Integer number); } \ No newline at end of file diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/GoodsMenuDto.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/GoodsMenuDto.java index 9948c65..d8f67fa 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/GoodsMenuDto.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/GoodsMenuDto.java @@ -1,25 +1,25 @@ package com.siam.package_goods.model.dto; import com.siam.package_goods.entity.Goods; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Date; public class GoodsMenuDto extends Goods { - @ApiModelProperty(notes = "菜单id") + @Schema(description = "菜单id") private Integer menuId; - @ApiModelProperty(notes = "菜单名称") + @Schema(description = "菜单名称") private String menuName; - @ApiModelProperty(notes = "指定查询状态为 2=已上架 4=售罄 的商品") + @Schema(description = "指定查询状态为 2=已上架 4=售罄 的商品") private Boolean goodsStatusIn2And4; - @ApiModelProperty(notes = "开始时间") + @Schema(description = "开始时间") private Date startTime; - @ApiModelProperty(notes = "结束时间") + @Schema(description = "结束时间") private Date endTime; public Integer getMenuId() { diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/GoodsSpecificationDto.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/GoodsSpecificationDto.java index fd9d277..e510dda 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/GoodsSpecificationDto.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/GoodsSpecificationDto.java @@ -1,27 +1,27 @@ package com.siam.package_goods.model.dto; import com.siam.package_goods.entity.Goods; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.math.BigDecimal; public class GoodsSpecificationDto extends Goods { - @ApiModelProperty(notes = "规格id") + @Schema(description = "规格id") private Integer specificationId; - @ApiModelProperty(notes = "规格名称") + @Schema(description = "规格名称") private String specificationName; - @ApiModelProperty(notes = "商品规格选项id") + @Schema(description = "商品规格选项id") private Integer specificationOptionId; - @ApiModelProperty(notes = "商品规格选项名称") + @Schema(description = "商品规格选项名称") private String specificationOptionName; - @ApiModelProperty(notes = "商品规格选项单价/加价金额") + @Schema(description = "商品规格选项单价/加价金额") private BigDecimal specificationOptionPrice; - @ApiModelProperty(notes = "商品规格选项库存 1代表有货,0代表无货") + @Schema(description = "商品规格选项库存 1代表有货,0代表无货") private Integer specificationOptionStock; public Integer getSpecificationId() { diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/GoodsSpecificationDto11.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/GoodsSpecificationDto11.java index 325ea90..eeaa58a 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/GoodsSpecificationDto11.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/GoodsSpecificationDto11.java @@ -1,13 +1,13 @@ package com.siam.package_goods.model.dto; import com.siam.package_goods.entity.GoodsSpecification; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; public class GoodsSpecificationDto11 extends GoodsSpecification { - @ApiModelProperty(notes = "商品名称") + @Schema(description = "商品名称") private String goodsName; - @ApiModelProperty(notes = "商品主图") + @Schema(description = "商品主图") private String goodsMainImage; public String getGoodsName() { diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/GoodsSpecificationOptionDto.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/GoodsSpecificationOptionDto.java index a44e58d..85097ad 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/GoodsSpecificationOptionDto.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/GoodsSpecificationOptionDto.java @@ -1,19 +1,19 @@ package com.siam.package_goods.model.dto; import com.siam.package_goods.entity.GoodsSpecificationOption; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.math.BigDecimal; import java.util.List; public class GoodsSpecificationOptionDto extends GoodsSpecificationOption { - @ApiModelProperty(notes = "规格名称") + @Schema(description = "规格名称") private String specificationName; - @ApiModelProperty(notes = "商品名称") + @Schema(description = "商品名称") private String goodsName; - @ApiModelProperty(notes = "商品主图") + @Schema(description = "商品主图") private String goodsMainImage; List ids; diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/internal/MemberGoodsCollectDto.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/internal/MemberGoodsCollectDto.java index 1f1110b..b5faa95 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/internal/MemberGoodsCollectDto.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/dto/internal/MemberGoodsCollectDto.java @@ -1,14 +1,14 @@ package com.siam.package_goods.model.dto.internal; import com.siam.package_goods.entity.internal.MemberGoodsCollect; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import com.baomidou.mybatisplus.annotation.TableField; @Data public class MemberGoodsCollectDto extends MemberGoodsCollect { - @ApiModelProperty(notes = "商品名称") + @Schema(description = "商品名称") private String goodsName; diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/param/GoodsParam.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/param/GoodsParam.java index 3f4c88f..081c342 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/param/GoodsParam.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/param/GoodsParam.java @@ -4,7 +4,7 @@ import com.siam.package_goods.entity.Goods; import lombok.Data; -import javax.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotBlank; import java.util.Date; import java.util.List; diff --git a/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/param/SearchParam.java b/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/param/SearchParam.java index c787d3a..7f4660e 100644 --- a/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/param/SearchParam.java +++ b/siam-goods/goods-api/src/main/java/com/siam/package_goods/model/param/SearchParam.java @@ -2,7 +2,7 @@ import lombok.Data; -import javax.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotBlank; @Data public class SearchParam { diff --git a/siam-goods/goods-provider/pom.xml b/siam-goods/goods-provider/pom.xml index 4d729e5..76b0a54 100644 --- a/siam-goods/goods-provider/pom.xml +++ b/siam-goods/goods-provider/pom.xml @@ -16,8 +16,6 @@ UTF-8 - 1.8 - 1.8 @@ -102,54 +100,42 @@ org.springframework.boot spring-boot-starter-data-elasticsearch - 2.1.4.RELEASE - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - 2.1.2.RELEASE - - - + com.alibaba.cloud - spring-cloud-starter-alibaba-seata - 2021.1 - - - io.seata - seata-spring-boot-starter - - + spring-cloud-starter-alibaba-nacos-discovery + - io.seata - seata-spring-boot-starter - 1.3.0 + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config org.springframework.boot spring-boot-starter-actuator - 2.3.3.RELEASE io.micrometer micrometer-registry-prometheus - 1.5.4 net.logstash.logback logstash-logback-encoder - 6.6 + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui @@ -159,7 +145,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 com.siam.package_goods.GoodsApplication diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/GoodsApplication.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/GoodsApplication.java index 6156cba..c28aaad 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/GoodsApplication.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/GoodsApplication.java @@ -1,16 +1,20 @@ package com.siam.package_goods; -import org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.EnableAspectJAutoProxy; @EnableFeignClients("com.siam") -@EnableEurekaClient -@SpringBootApplication(scanBasePackages = "com.siam", exclude = {RocketMQAutoConfiguration.class}) +@EnableDiscoveryClient +@SpringBootApplication(scanBasePackages = "com.siam", exclude = { + MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class +}) @MapperScan(basePackages = {"com.siam.**.mapper"}) public class GoodsApplication { diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/config/MybatisPlusConfig.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/config/MybatisPlusConfig.java index 0d9b7a1..16f53a7 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/config/MybatisPlusConfig.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/config/MybatisPlusConfig.java @@ -1,6 +1,8 @@ package com.siam.package_goods.config; -import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -19,8 +21,11 @@ public class MybatisPlusConfig { * 分页插件 */ @Bean - public PaginationInterceptor paginationInterceptor() { - return new PaginationInterceptor(); + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); + interceptor.addInnerInterceptor(paginationInnerInterceptor); + return interceptor; } } \ No newline at end of file diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/config/Swagger2Config.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/config/Swagger2Config.java deleted file mode 100644 index 715019d..0000000 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/config/Swagger2Config.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.siam.package_goods.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; - -@Configuration -@EnableSwagger2 -public class Swagger2Config { - - @Bean - public Docket createRestApi() { - return new Docket(DocumentationType.SWAGGER_2) - .apiInfo(apiInfo()) - .select() - .apis(RequestHandlerSelectors.basePackage("com.siam"))//扫描包路径 - .paths(PathSelectors.any()) - .build(); - } - - // 构建api文档的详细信息函数,注意这里的注解引用的是哪个 - private ApiInfo apiInfo() { - return new ApiInfoBuilder() - .title("暹罗外卖-商品服务接口文档")//页面标题 - .description("")//描述 - .version("1.0")//版本号 - .build(); - } -} \ No newline at end of file diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsAccessoriesController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsAccessoriesController.java index ca9e6f9..2336a8a 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsAccessoriesController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsAccessoriesController.java @@ -8,8 +8,9 @@ import com.siam.package_goods.service.GoodsAccessoriesService; import com.siam.package_goods.model.example.GoodsSpecificationOptionExample; import com.siam.package_goods.service.GoodsSpecificationOptionService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -20,7 +21,7 @@ @RestController @RequestMapping(value = "/rest/admin/goodsAccessories") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台商品辅料模块相关接口", description = "AdminGoodsAccessoriesController") +@Tag(name = "后台商品辅料模块相关接口", description = "AdminGoodsAccessoriesController") public class AdminGoodsAccessoriesController { @Autowired @@ -29,7 +30,7 @@ public class AdminGoodsAccessoriesController { @Autowired private GoodsSpecificationOptionService goodsSpecificationOptionService; - @ApiOperation(value = "商品辅料列表") + @Operation(summary = "商品辅料列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) GoodsAccessories param){ BasicData basicResult = new BasicData(); @@ -38,7 +39,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) GoodsAccessories par return BasicResult.success(page); } - @ApiOperation(value = "新增商品辅料") + @Operation(summary = "新增商品辅料") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) GoodsAccessories param){ BasicResult basicResult = new BasicResult(); @@ -54,7 +55,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) GoodsAccessories p } - @ApiOperation(value = "修改商品辅料") + @Operation(summary = "修改商品辅料") @PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) GoodsAccessories param){ BasicResult basicResult = new BasicResult(); @@ -73,7 +74,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) GoodsAccessories p } - @ApiOperation(value = "删除商品辅料") + @Operation(summary = "删除商品辅料") @DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) GoodsAccessories param){ BasicResult basicResult = new BasicResult(); diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsController.java index e6a21ac..4719992 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsController.java @@ -17,10 +17,26 @@ //import com.siam.package_promotion.entity.CouponsGoodsRelation; //import com.siam.package_promotion.feign.CouponsFeignApi; //import com.siam.package_promotion.feign.CouponsGoodsRelationFeignApi; -//import io.swagger.annotations.Api; -//import io.swagger.annotations.ApiImplicitParam; -//import io.swagger.annotations.ApiImplicitParams; -//import io.swagger.annotations.ApiOperation; +//import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +//import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +//import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +//import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; //import org.apache.commons.lang3.StringUtils; //import org.apache.poi.xssf.usermodel.XSSFWorkbook; //import org.springframework.beans.factory.annotation.Autowired; @@ -29,7 +45,7 @@ //import org.springframework.web.bind.annotation.*; //import org.springframework.web.multipart.MultipartFile; // -//import javax.servlet.http.HttpServletResponse; +//import jakarta.servlet.http.HttpServletResponse; //import java.io.IOException; //import java.io.InputStream; //import java.io.OutputStream; @@ -40,7 +56,7 @@ //@RestController //@RequestMapping(value = "/rest/admin/goods") //@Transactional(rollbackFor = Exception.class) -//@Api(tags = "后台商品模块相关接口", description = "AdminGoodsController") +//@Tag(name = "后台商品模块相关接口", description = "AdminGoodsController") //public class AdminGoodsController { // @Autowired // private GoodsService goodsService; @@ -69,7 +85,7 @@ // @Autowired // private CouponsGoodsRelationFeignApi couponsGoodsRelationFeignApi; // -// @ApiOperation(value = "商品列表") +// @Operation(summary = "商品列表") // @PostMapping(value = "/list") // public BasicResult list(@RequestBody @Validated(value = {}) GoodsMenuDto param){ // BasicData basicResult = new BasicData(); @@ -80,7 +96,7 @@ // } // // -// @ApiOperation(value = "新增商品") +// @Operation(summary = "新增商品") // @PostMapping(value = "/insert") // public BasicResult insert(@RequestBody @Validated(value = {}) GoodsMenuDto param){ // BasicResult basicResult = new BasicResult(); @@ -141,7 +157,7 @@ // return basicResult; // } // -// @ApiOperation(value = "修改商品") +// @Operation(summary = "修改商品") // @PostMapping(value = "/update") // public BasicResult update(@RequestBody @Validated(value = {}) GoodsMenuDto param){ // BasicResult basicResult = new BasicResult(); @@ -185,7 +201,7 @@ // return basicResult; // } // -// @ApiOperation(value = "删除商品") +// @Operation(summary = "删除商品") // @PostMapping(value = "/delete") // public BasicResult delete(@RequestBody @Validated(value = {}) GoodsMenuDto param){ // BasicResult basicResult = new BasicResult(); @@ -223,7 +239,7 @@ // return basicResult; // } // -// @ApiOperation(value = "导入商品Excel报表") +// @Operation(summary = "导入商品Excel报表") // @PostMapping(value = "/import") // public BasicResult importGoods(@RequestParam(value = "file", required = true) MultipartFile file){ // BasicResult basicResult = new BasicResult(); @@ -266,12 +282,8 @@ // return basicResult; // } // -// @ApiOperation(value = "导出商品Excel报表") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), -// @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), -// }) -// @GetMapping(value = "/export") +// @Operation(summary = "导出商品Excel报表") +//// @GetMapping(value = "/export") // public void exportGoods(int pageNo, int pageSize, Goods goods, HttpServletResponse response){ // try { // // 生成Excel数据 @@ -301,12 +313,8 @@ // } // } // -// @ApiOperation(value = "菜单状态修改(启用或禁用)") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "ids", value = "商品主键id集合(批量删除时id以逗号分隔)", required = true, paramType = "query", dataType = "String"), -// @ApiImplicitParam(name = "status", value = "是否启用 0-上架、1-下架", required = true, paramType = "query", dataType = "int") -// }) -// @DeleteMapping(value = "/update_status") +// @Operation(summary = "菜单状态修改(启用或禁用)") +//// @DeleteMapping(value = "/update_status") // public BasicResult updateStatus(List ids,Integer status){ // BasicResult basicResult = new BasicResult(); // @@ -318,11 +326,8 @@ // } // // -// @ApiOperation(value = "获取单个商品详情信息") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "id", value = "商品表主键id", required = true, paramType = "query", dataType = "int"), -// }) -// @PostMapping(value = "/getById") +// @Operation(summary = "获取单个商品详情信息") +//// @PostMapping(value = "/getById") // public BasicResult getById(@RequestBody @Validated(value = {}) GoodsMenuDto param){ // BasicData basicResult = new BasicData(); // @@ -346,38 +351,8 @@ // } // // -// /*@ApiOperation(value = "商品规格信息列表") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "id", value = "商品表主键id", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "name", value = "商品名称", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "categoryId", value = "分类id", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "categoryName", value = "分类名称", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "brandId", value = "品牌id", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "brandName", value = "品牌名称", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "mainImage", value = "商品主图", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "subImages", value = "商品子图", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "specList", value = "商品规格", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "detail", value = "商品详情", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "detailImages", value = "详情图片", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "price", value = "一口价", required = false, paramType = "query", dataType = "BigDecimal"), -// @ApiImplicitParam(name = "salePrice", value = "折扣价", required = false, paramType = "query", dataType = "BigDecimal"), -// @ApiImplicitParam(name = "monthlySales", value = "月销量", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "totalSales", value = "累计销量", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "totalComments", value = "累计评价", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "stock", value = "库存", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "isHot", value = "是否热门", required = false, paramType = "query", dataType = "Boolean"), -// @ApiImplicitParam(name = "isNew", value = "是否新品", required = false, paramType = "query", dataType = "Boolean"), -// @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "specificationId", value = "规格id", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "specificationName", value = "规格名称", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "specificationOptionId", value = "商品规格选项id", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "specificationOptionName", value = "商品规格选项名称", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "specificationOptionPrice", value = "商品规格选项单价/加价金额", required = false, paramType = "query", dataType = "BigDecimal"), -// @ApiImplicitParam(name = "specificationOptionStock", value = "商品规格选项库存 1代表有货,0代表无货", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), -// @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), -// }) -// @PostMapping(value = "/listSpecification") +// /*@Operation(summary = "商品规格信息列表") +//// @PostMapping(value = "/listSpecification") // public BasicResult listSpecification(int pageNo, int pageSize, GoodsSpecificationDto goodsSpecificationDto){ // BasicData basicResult = new BasicData(); // diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsRawmaterialRelationController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsRawmaterialRelationController.java index a428d29..3899b55 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsRawmaterialRelationController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsRawmaterialRelationController.java @@ -14,8 +14,9 @@ import com.siam.package_goods.entity.Rawmaterial; import com.siam.package_goods.service.RawmaterialService; import com.siam.package_user.model.param.AdminParam; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -28,7 +29,7 @@ @RestController @RequestMapping(value = "/rest/admin/goodsRawmaterialRelation") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台原料配比模块相关接口", description = "AdminGoodsRawmaterialRelationController") +@Tag(name = "后台原料配比模块相关接口", description = "AdminGoodsRawmaterialRelationController") public class AdminGoodsRawmaterialRelationController { @Autowired @@ -40,7 +41,7 @@ public class AdminGoodsRawmaterialRelationController { @Autowired private GoodsService goodsService; - @ApiOperation(value = "原料配比列表") + @Operation(summary = "原料配比列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) GoodsRawmaterialRelation param){ BasicData basicResult = new BasicData(); @@ -49,7 +50,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) GoodsRawmaterialRela return BasicResult.success(page); } - @ApiOperation(value = "设置原料配比") + @Operation(summary = "设置原料配比") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) AdminParam param){ BasicResult basicResult = new BasicResult(); @@ -120,7 +121,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) AdminParam param){ } - @ApiOperation(value = "修改原料配比") + @Operation(summary = "修改原料配比") @PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) GoodsRawmaterialRelation param){ BasicResult basicResult = new BasicResult(); @@ -135,7 +136,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) GoodsRawmaterialRe } - @ApiOperation(value = "删除原料配比") + @Operation(summary = "删除原料配比") @DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) GoodsRawmaterialRelation param){ BasicResult basicResult = new BasicResult(); @@ -157,14 +158,14 @@ public BasicResult delete(@RequestBody @Validated(value = {}) GoodsRawmaterialRe return basicResult; } - @ApiOperation(value = "查询原料配比信息") + @Operation(summary = "查询原料配比信息") @PostMapping(value = "/find/goodsRawmaterialRelation") public BasicResult findGoodsRawmaterialRelation(@RequestBody @Validated(value = {}) GoodsRawmaterialRelation param){ Page page = goodsRawmaterialRelationService.findGoodsRawmaterialRelation(param.getPageNo(), param.getPageSize(), param.getGoodsName()); return BasicResult.success(page); } - @ApiOperation(value = "通过商品查询原料配比信息详情") + @Operation(summary = "通过商品查询原料配比信息详情") @PostMapping(value = "/find/goodsRawmaterialRelationByGoodsId") public BasicResult findGoodsRawmaterialRelationByGoodsId(@RequestBody @Validated(value = {}) GoodsRawmaterialRelation param){ Page page = goodsRawmaterialRelationService.selectByGoodsId(param.getPageNo(), param.getPageSize(), param.getGoodsId()); diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsSpecificationController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsSpecificationController.java index dc684f0..dcb7ab5 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsSpecificationController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsSpecificationController.java @@ -7,8 +7,11 @@ import com.siam.package_common.entity.BasicResult; import com.siam.package_goods.entity.GoodsSpecification; import com.siam.package_goods.model.example.GoodsSpecificationExample; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -20,12 +23,12 @@ @RestController @RequestMapping(value = "/rest/admin/goodsSpecification") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台商品规格模块相关接口", description = "AdminGoodsSpecificationController") +@Tag(name = "后台商品规格模块相关接口", description = "AdminGoodsSpecificationController") public class AdminGoodsSpecificationController { @Autowired private GoodsSpecificationService goodsSpecificationService; - @ApiOperation(value = "商品规格列表") + @Operation(summary = "商品规格列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) GoodsSpecification param){ BasicData basicResult = new BasicData(); @@ -36,7 +39,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) GoodsSpecification p } - @ApiOperation(value = "修改商品规格") + @Operation(summary = "修改商品规格") @PostMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) GoodsSpecification param){ BasicResult basicResult = new BasicResult(); @@ -69,13 +72,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) GoodsSpecification return basicResult; } - /*@ApiOperation(value = "新增商品规格") - @ApiImplicitParams({ - @ApiImplicitParam(name = "name", value = "规格名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序号", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - }) - @PostMapping(value = "/insert") + /*@Operation(summary = "新增商品规格")@PostMapping(value = "/insert") public BasicResult insert(Specification specification){ BasicResult basicResult = new BasicResult(); @@ -87,11 +84,7 @@ public BasicResult insert(Specification specification){ return basicResult; }*/ - /*@ApiOperation(value = "删除商品规格(含批量操作)") - @ApiImplicitParams({ - @ApiImplicitParam(name = "ids", value = "商品规格表主键id(批量删除时id以逗号分隔)", required = true, paramType = "query", dataType = "string"), - }) - @PostMapping(value = "/delete") + /*@Operation(summary = "删除商品规格(含批量操作)")@PostMapping(value = "/delete") public BasicResult delete(@RequestParam(value = "ids", required = true) List ids){ BasicResult basicResult = new BasicResult(); diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsSpecificationOptionController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsSpecificationOptionController.java index 9f97877..3cd7ad8 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsSpecificationOptionController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminGoodsSpecificationOptionController.java @@ -12,8 +12,11 @@ import com.siam.package_goods.model.example.GoodsSpecificationOptionExample; import com.siam.package_goods.model.dto.GoodsSpecificationOptionDto; import com.siam.package_goods.service.GoodsSpecificationOptionService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -26,7 +29,7 @@ @RestController @RequestMapping(value = "/rest/admin/goodsSpecificationOption") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台商品规格选项模块相关接口", description = "AdminGoodsSpecificationOptionController") +@Tag(name = "后台商品规格选项模块相关接口", description = "AdminGoodsSpecificationOptionController") public class AdminGoodsSpecificationOptionController { @Autowired private GoodsSpecificationOptionService goodsSpecificationOptionService; @@ -37,7 +40,7 @@ public class AdminGoodsSpecificationOptionController { @Autowired private GoodsAccessoriesService goodsAccessoriesService; - @ApiOperation(value = "商品规格选项列表") + @Operation(summary = "商品规格选项列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) GoodsSpecificationOptionDto param){ BasicData basicResult = new BasicData(); @@ -47,7 +50,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) GoodsSpecificationOp return BasicResult.success(page); } - @ApiOperation(value = "添加商品规格选项") + @Operation(summary = "添加商品规格选项") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) GoodsSpecificationOptionDto param){ BasicData basicResult = new BasicData(); @@ -107,7 +110,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) GoodsSpecification return basicResult; } - @ApiOperation(value = "修改商品规格选项") + @Operation(summary = "修改商品规格选项") @PostMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) GoodsSpecificationOptionDto param){ BasicResult basicResult = new BasicResult(); @@ -171,7 +174,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) GoodsSpecification return basicResult; } - @ApiOperation(value = "删除商品规格选项(含批量操作)") + @Operation(summary = "删除商品规格选项(含批量操作)") @PostMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) GoodsSpecificationOptionDto param){ BasicResult basicResult = new BasicResult(); @@ -203,11 +206,7 @@ public BasicResult delete(@RequestBody @Validated(value = {}) GoodsSpecification return basicResult; } - /*@ApiOperation(value = "生成商品公共口味") - @ApiImplicitParams({ - @ApiImplicitParam(name = "goodsId", value = "商品id", required = true, paramType = "query", dataType = "int") - }) - @PostMapping(value = "/insertPublicSpecification") + /*@Operation(summary = "生成商品公共口味")@PostMapping(value = "/insertPublicSpecification") public BasicResult insertPublicSpecification(int goodsId){ BasicResult basicResult = new BasicResult(); diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminMenuController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminMenuController.java index 52a6552..356be97 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminMenuController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminMenuController.java @@ -8,8 +8,9 @@ import com.siam.package_goods.service.MenuService; import com.siam.package_goods.model.example.MenuGoodsRelationExample; import com.siam.package_goods.service.MenuGoodsRelationService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -20,7 +21,7 @@ @RestController @RequestMapping(value = "/rest/admin/menu") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台菜单分类模块相关接口", description = "AdminMenuController") +@Tag(name = "后台菜单分类模块相关接口", description = "AdminMenuController") public class AdminMenuController { @Autowired @@ -29,7 +30,7 @@ public class AdminMenuController { @Autowired private MenuGoodsRelationService menuGoodsRelationService; - @ApiOperation(value = "菜单列表") + @Operation(summary = "菜单列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) Menu param){ BasicData basicResult = new BasicData(); @@ -38,7 +39,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) Menu param){ return BasicResult.success(page); } - @ApiOperation(value = "菜单创建") + @Operation(summary = "菜单创建") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) Menu param){ BasicResult basicResult = new BasicResult(); @@ -54,7 +55,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) Menu param){ } - @ApiOperation(value = "菜单修改") + @Operation(summary = "菜单修改") @PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) Menu param){ BasicResult basicResult = new BasicResult(); @@ -69,7 +70,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) Menu param){ } - @ApiOperation(value = "菜单删除") + @Operation(summary = "菜单删除") @DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) Menu param){ BasicResult basicResult = new BasicResult(); diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminRawmaterialController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminRawmaterialController.java index 5895292..ddf1b73 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminRawmaterialController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminRawmaterialController.java @@ -8,8 +8,9 @@ import com.siam.package_goods.service.GoodsRawmaterialRelationService; import com.siam.package_goods.entity.Rawmaterial; import com.siam.package_goods.service.RawmaterialService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -20,7 +21,7 @@ @RestController @RequestMapping(value = "/rest/admin/rawmaterial") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台原料模块相关接口", description = "AdminRawmaterialController") +@Tag(name = "后台原料模块相关接口", description = "AdminRawmaterialController") public class AdminRawmaterialController { @Autowired private RawmaterialService rawmaterialService; @@ -28,7 +29,7 @@ public class AdminRawmaterialController { @Autowired private GoodsRawmaterialRelationService goodsRawmaterialRelationService; - @ApiOperation(value = "原料列表") + @Operation(summary = "原料列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) Rawmaterial rawmaterial){ BasicData basicResult = new BasicData(); @@ -37,7 +38,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) Rawmaterial rawmater return BasicResult.success(page); } - @ApiOperation(value = "新增原料") + @Operation(summary = "新增原料") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) Rawmaterial rawmaterial){ BasicResult basicResult = new BasicResult(); @@ -53,7 +54,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) Rawmaterial rawmat } - @ApiOperation(value = "修改原料") + @Operation(summary = "修改原料") @PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) Rawmaterial rawmaterial){ BasicResult basicResult = new BasicResult(); @@ -68,7 +69,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) Rawmaterial rawmat } - @ApiOperation(value = "删除原料") + @Operation(summary = "删除原料") @DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) Rawmaterial param){ BasicResult basicResult = new BasicResult(); diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminShoppingCartController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminShoppingCartController.java index 651c709..463d6f2 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminShoppingCartController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminShoppingCartController.java @@ -6,8 +6,9 @@ import com.siam.package_common.constant.BasicResultCode; import com.siam.package_goods.entity.ShoppingCart; import com.siam.package_goods.service.ShoppingCartService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -16,12 +17,12 @@ @RestController @RequestMapping(value = "/rest/admin/shoppingCart") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台购物车模块相关接口", description = "AdminShoppingCartController") +@Tag(name = "后台购物车模块相关接口", description = "AdminShoppingCartController") public class AdminShoppingCartController { @Autowired private ShoppingCartService shoppingCartService; - @ApiOperation(value = "购物车列表") + @Operation(summary = "购物车列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) ShoppingCart shoppingCart){ BasicData basicResult = new BasicData(); @@ -32,7 +33,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) ShoppingCart shoppin } - @ApiOperation(value = "新增购物车") + @Operation(summary = "新增购物车") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) ShoppingCart shoppingCart){ BasicResult basicResult = new BasicResult(); @@ -45,7 +46,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) ShoppingCart shopp return basicResult; } - @ApiOperation(value = "修改购物车") + @Operation(summary = "修改购物车") @PostMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) ShoppingCart shoppingCart){ BasicResult basicResult = new BasicResult(); @@ -58,7 +59,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) ShoppingCart shopp return basicResult; } - @ApiOperation(value = "删除购物车(含批量操作)") + @Operation(summary = "删除购物车(含批量操作)") @PostMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) ShoppingCart param){ BasicResult basicResult = new BasicResult(); diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminStatisticsController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminStatisticsController.java index aa2e33c..32e8d44 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminStatisticsController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/AdminStatisticsController.java @@ -3,7 +3,8 @@ import com.siam.package_common.entity.BasicResult; import com.siam.package_goods.model.param.StatisticsParam; import com.siam.package_goods.service.StatisticsService; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -17,7 +18,7 @@ @RestController @RequestMapping(value = "/rest/admin/statistics") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台统计模块相关接口", description = "AdminAdvertisementController") +@Tag(name = "后台统计模块相关接口", description = "AdminAdvertisementController") public class AdminStatisticsController { @Autowired diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/internal/AdminPointsMallStatisticsController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/internal/AdminPointsMallStatisticsController.java index 90e9e0c..8392ba3 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/internal/AdminPointsMallStatisticsController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/admin/internal/AdminPointsMallStatisticsController.java @@ -3,7 +3,8 @@ import com.siam.package_common.entity.BasicResult; import com.siam.package_goods.model.param.StatisticsParam; import com.siam.package_goods.service.internal.PointsMallStatisticsService; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -17,7 +18,7 @@ @RestController @RequestMapping(value = "/rest/admin/statistics/pointsMall") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台统计模块相关接口", description = "AdminAdvertisementController") +@Tag(name = "后台统计模块相关接口", description = "AdminAdvertisementController") public class AdminPointsMallStatisticsController { @Autowired diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/GoodsController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/GoodsController.java index 3f84b6d..fab6f4a 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/GoodsController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/GoodsController.java @@ -1,7 +1,6 @@ package com.siam.package_goods.controller.member; import cn.hutool.core.convert.Convert; -import com.alibaba.druid.support.json.JSONUtils; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.siam.package_common.constant.BasicResultCode; import com.siam.package_common.constant.Quantity; @@ -19,8 +18,11 @@ import com.siam.package_user.model.param.AdminParam; import com.siam.package_util.entity.Setting; import com.siam.package_util.feign.SettingFeignApi; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; @@ -38,7 +40,7 @@ @RestController @RequestMapping(value = "/rest/goods") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商品模块相关接口", description = "GoodsController") +@Tag(name = "商品模块相关接口", description = "GoodsController") public class GoodsController { @Autowired private GoodsService goodsService; @@ -58,34 +60,7 @@ public class GoodsController { @Autowired private BaiduMapUtils baiduMapUtils; - /*@ApiOperation(value = "商品列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "商品名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "categoryId", value = "分类id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "categoryName", value = "分类名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "brandId", value = "品牌id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "brandName", value = "品牌名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "mainImage", value = "商品主图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "subImages", value = "商品子图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specList", value = "商品规格", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "detail", value = "商品详情", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "detailImages", value = "详情图片", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "一口价", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "salePrice", value = "折扣价", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "monthlySales", value = "月销量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "totalSales", value = "累计销量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "totalComments", value = "累计评价", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "stock", value = "库存", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "productTime", value = "制作时长(分钟)", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "exchangePoints", value = "兑换商品所需积分数量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isHot", value = "是否热门", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "isNew", value = "是否新品", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "status", value = "状态 1=下架 0=上架", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) - @PostMapping(value = "/list") + /*@Operation(summary = "商品列表")@PostMapping(value = "/list") public BasicResult list(int pageNo, int pageSize, Goods goods){ BasicData basicResult = new BasicData(); @@ -193,11 +168,7 @@ public BasicResult listByMenuId(@RequestBody @Validated(value = {}) GoodsMenuDto } - /*@ApiOperation(value = "查询商品的规格组合信息") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品表主键id", required = true, paramType = "query", dataType = "int"), - }) - @PostMapping(value = "/selectSpecificationById") + /*@Operation(summary = "查询商品的规格组合信息")@PostMapping(value = "/selectSpecificationById") public BasicResult selectSpecificationById(GoodsSpecificationDto goodsSpecificationDto){ BasicData basicResult = new BasicData(); @@ -223,7 +194,7 @@ public BasicResult selectSpecificationById(GoodsSpecificationDto goodsSpecificat return basicResult; }*/ - /*@ApiOperation(value = "本月上新商品列表") + /*@Operation(summary = "本月上新商品列表") @PostMapping(value = "/weekNewGoodsList") public BasicResult weekNewGoodsList(){ BasicData basicResult = new BasicData(); @@ -238,7 +209,7 @@ public BasicResult weekNewGoodsList(){ return basicResult; }*/ - /*@ApiOperation(value = "好友推荐商品列表") + /*@Operation(summary = "好友推荐商品列表") @PostMapping(value = "/recommendGoodsList") public BasicResult recommendGoodsList(){ BasicData basicResult = new BasicData(); @@ -269,7 +240,7 @@ public BasicResult recommendGoodsList(){ return basicResult; }*/ - @ApiOperation(value = "猜你喜欢商品列表") + @Operation(summary = "猜你喜欢商品列表") @PostMapping(value = "/guessLikeGoodsList") public BasicResult guessLikeGoodsList(@RequestBody @Validated(value = {}) AdminParam param){ BasicData basicResult = new BasicData(); @@ -300,7 +271,7 @@ public BasicResult guessLikeGoodsList(@RequestBody @Validated(value = {}) AdminP return basicResult; } - @ApiOperation(value = "首页商品推荐列表") + @Operation(summary = "首页商品推荐列表") @PostMapping(value = "/homePage/recommendGoodsList") public BasicResult recommendGoodsListOfHomePage(@RequestBody @Validated(value = {}) Goods param ){ //首页商品推荐位置一共有6件商品 -- 改成2件商品 diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/GoodsSpecificationController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/GoodsSpecificationController.java index 44ad934..5f5c3d5 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/GoodsSpecificationController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/GoodsSpecificationController.java @@ -1,7 +1,8 @@ package com.siam.package_goods.controller.member; import com.siam.package_goods.service.GoodsSpecificationService; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RequestMapping; @@ -10,7 +11,7 @@ @RestController @RequestMapping(value = "/rest/goodsSpecification") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商品规格模块相关接口", description = "GoodsSpecificationController") +@Tag(name = "商品规格模块相关接口", description = "GoodsSpecificationController") public class GoodsSpecificationController { @Autowired private GoodsSpecificationService goodsSpecificationService; diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/GoodsSpecificationOptionController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/GoodsSpecificationOptionController.java index c0cd3a1..91bd5b6 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/GoodsSpecificationOptionController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/GoodsSpecificationOptionController.java @@ -6,10 +6,10 @@ import com.siam.package_common.constant.BasicResultCode; import com.siam.package_goods.model.dto.GoodsSpecificationOptionDto; import com.siam.package_goods.service.GoodsSpecificationOptionService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -26,15 +26,12 @@ @RestController @RequestMapping(value = "/rest/goodsSpecificationOption") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商品规格选项模块相关接口", description = "GoodsSpecificationOptionController") +@Tag(name = "商品规格选项模块相关接口", description = "GoodsSpecificationOptionController") public class GoodsSpecificationOptionController { @Autowired private GoodsSpecificationOptionService goodsSpecificationOptionService; - @ApiOperation(value = "查询商品规格选项信息") - @ApiImplicitParams({ - @ApiImplicitParam(name = "goodsId", value = "商品id", required = true, paramType = "query", dataType = "int"), - }) + @Operation(summary = "查询商品规格选项信息") @PostMapping(value = "/selectByGoodsId") public BasicResult list(@RequestBody @Validated(value = {}) GoodsSpecificationOptionDto goodsSpecificationOptionDto){ BasicData basicResult = new BasicData(); diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/MRecommendGoodsController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/MRecommendGoodsController.java index c908213..8f5f6b4 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/MRecommendGoodsController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/MRecommendGoodsController.java @@ -7,7 +7,8 @@ import com.siam.package_common.exception.StoneCustomerException; import com.siam.package_goods.entity.MerchantRecommendGoods; import com.siam.package_goods.service.MerchantRecommendGoodsService; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -23,7 +24,7 @@ @RestController @RequestMapping(value = "/rest/merchantRecommendGoods") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家推荐商品模块相关接口", description = "MRecommendGoodsController") +@Tag(name = "商家推荐商品模块相关接口", description = "MRecommendGoodsController") public class MRecommendGoodsController { @Autowired diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/MenuController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/MenuController.java index 7992333..1f8fe29 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/MenuController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/MenuController.java @@ -3,7 +3,8 @@ import com.siam.package_common.entity.BasicResult; import com.siam.package_goods.entity.Menu; import com.siam.package_goods.service.MenuService; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -14,7 +15,7 @@ @RestController @RequestMapping(value = "/rest/menu") @Transactional(rollbackFor = Exception.class) -@Api(tags = "菜单分类模块相关接口", description = "MenuController") +@Tag(name = "菜单分类模块相关接口", description = "MenuController") public class MenuController{ @Autowired diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/ShoppingCartController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/ShoppingCartController.java index 95479fd..8dca04d 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/ShoppingCartController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/ShoppingCartController.java @@ -14,7 +14,8 @@ import com.siam.package_goods.service.ShoppingCartService; import com.siam.package_goods.service.GoodsSpecificationOptionService; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -24,7 +25,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -34,7 +35,7 @@ @RestController @RequestMapping(value = "/rest/member/shoppingCart") @Transactional(rollbackFor = Exception.class) -@Api(tags = "购物车模块相关接口", description = "ShoppingCartController") +@Tag(name = "购物车模块相关接口", description = "ShoppingCartController") public class ShoppingCartController { @Autowired diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/internal/MemberGoodsCollectController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/internal/MemberGoodsCollectController.java index 820b5cc..cc6f102 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/internal/MemberGoodsCollectController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/member/internal/MemberGoodsCollectController.java @@ -15,14 +15,15 @@ import com.siam.package_goods.model.example.internal.MemberGoodsCollectExample; import com.siam.package_goods.service.internal.MemberGoodsCollectService; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.List; import java.util.Map; @@ -30,7 +31,7 @@ @RestController @RequestMapping(value = "/rest/member/goodsCollect") @Transactional(rollbackFor = Exception.class) -@Api(tags = "用户商品收藏相关接口", description = "MemberGoodsCollectController") +@Tag(name = "用户商品收藏相关接口", description = "MemberGoodsCollectController") public class MemberGoodsCollectController { @Autowired diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsAccessoriesController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsAccessoriesController.java index 364390f..83d957b 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsAccessoriesController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsAccessoriesController.java @@ -8,10 +8,16 @@ import com.siam.package_goods.service.GoodsAccessoriesService; import com.siam.package_goods.model.example.GoodsSpecificationOptionExample; import com.siam.package_goods.service.GoodsSpecificationOptionService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -22,7 +28,7 @@ @RestController @RequestMapping(value = "/rest/merchant/goodsAccessories") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端商品辅料模块相关接口", description = "MerchantGoodsAccessoriesController") +@Tag(name = "商家端商品辅料模块相关接口", description = "MerchantGoodsAccessoriesController") public class MerchantGoodsAccessoriesController { @Autowired @@ -31,17 +37,7 @@ public class MerchantGoodsAccessoriesController { @Autowired private GoodsSpecificationOptionService goodsSpecificationOptionService; - @ApiOperation(value = "商品辅料列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品辅料表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "商品辅料名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "detail", value = "商品辅料详情描述", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - }) - @PostMapping(value = "/list") + @Operation(summary = "商品辅料列表")@PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) GoodsAccessories goodsAccessories){ BasicData basicResult = new BasicData(); Page page = goodsAccessoriesService.getListByPage(goodsAccessories.getPageNo(), goodsAccessories.getPageSize(), goodsAccessories); @@ -49,15 +45,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) GoodsAccessories goo return BasicResult.success(page); } - @ApiOperation(value = "新增商品辅料") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品辅料主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "商品辅料名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "detail", value = "商品辅料详情描述", required = false, paramType = "query", dataType = "string") - }) - @PostMapping(value = "/insert") + @Operation(summary = "新增商品辅料")@PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) GoodsAccessories goodsAccessories){ BasicResult basicResult = new BasicResult(); @@ -72,15 +60,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) GoodsAccessories g } - @ApiOperation(value = "修改商品辅料") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品辅料主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "商品辅料名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "detail", value = "商品辅料详情描述", required = false, paramType = "query", dataType = "string") - }) - @PutMapping(value = "/update") + @Operation(summary = "修改商品辅料")@PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) GoodsAccessories goodsAccessories){ BasicResult basicResult = new BasicResult(); @@ -98,11 +78,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) GoodsAccessories g } - @ApiOperation(value = "删除商品辅料") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品辅料主键id", required = true, paramType = "query", dataType = "int") - }) - @DeleteMapping(value = "/delete") + @Operation(summary = "删除商品辅料")@DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) GoodsAccessories param){ BasicResult basicResult = new BasicResult(); diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsController.java index b327010..fef7661 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsController.java @@ -24,10 +24,11 @@ import com.siam.package_util.feign.PictureUploadRecordFeignApi; import com.siam.package_util.model.example.PictureUploadRecordExample; import com.siam.package_util.model.param.PictureUploadRecordParam; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -37,7 +38,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.Date; import java.util.List; import java.util.Map; @@ -45,7 +46,7 @@ @RestController @RequestMapping(value = "/rest/merchant/goods") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端商品模块相关接口", description = "MerchantGoodsController") +@Tag(name = "商家端商品模块相关接口", description = "MerchantGoodsController") public class MerchantGoodsController { @Autowired private GoodsService goodsService; @@ -83,35 +84,7 @@ public class MerchantGoodsController { @Autowired private MerchantSessionManager merchantSessionManager; - @ApiOperation(value = "商品列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "商品名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "categoryId", value = "分类id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "categoryName", value = "分类名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "brandId", value = "品牌id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "brandName", value = "品牌名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "mainImage", value = "商品主图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "subImages", value = "商品子图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specList", value = "商品规格", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "detail", value = "商品详情", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "detailImages", value = "详情图片", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "一口价", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "salePrice", value = "折扣价", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "monthlySales", value = "月销量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "totalSales", value = "累计销量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "totalComments", value = "累计评价", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "stock", value = "库存", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "productTime", value = "制作时长(分钟)", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "exchangePoints", value = "兑换商品所需积分数量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isHot", value = "是否热门", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "isNew", value = "是否新品", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "menuId", value = "菜单id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "menuName", value = "菜单名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) + @Operation(summary = "商品列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) GoodsMenuDto goodsMenuDto, HttpServletRequest request){ BasicData basicResult = new BasicData(); @@ -126,31 +99,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) GoodsMenuDto goodsMe } - @ApiOperation(value = "新增商品") - @ApiImplicitParams({ - @ApiImplicitParam(name = "name", value = "商品名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "categoryId", value = "分类id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "categoryName", value = "分类名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "brandId", value = "品牌id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "brandName", value = "品牌名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "mainImage", value = "商品主图", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "subImages", value = "商品子图(多图上传)", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specList", value = "商品规格", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "detail", value = "商品详情", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "detailImages", value = "详情图片(多图上传)", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "一口价", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "salePrice", value = "折扣价", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "monthlySales", value = "月销量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "totalSales", value = "累计销量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "totalComments", value = "累计评价", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "stock", value = "库存", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "productTime", value = "制作时长(分钟)", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "exchangePoints", value = "兑换商品所需积分数量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isHot", value = "是否热门", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "isNew", value = "是否新品", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "menuId", value = "菜单id", required = false, paramType = "query", dataType = "int"), - }) + @Operation(summary = "新增商品") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) GoodsParam param, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); @@ -216,31 +165,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) GoodsParam param, } @MerchantPermission - @ApiOperation(value = "修改商品") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品表主键id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "商品名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "categoryId", value = "分类id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "categoryName", value = "分类名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "brandId", value = "品牌id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "brandName", value = "品牌名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "mainImage", value = "商品主图", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "subImages", value = "商品子图", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specList", value = "商品规格", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "detail", value = "商品详情", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "detailImages", value = "详情图片", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "一口价", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "salePrice", value = "折扣价", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "monthlySales", value = "月销量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "totalSales", value = "累计销量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "totalComments", value = "累计评价", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "stock", value = "库存", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "productTime", value = "制作时长(分钟)", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "exchangePoints", value = "兑换商品所需积分数量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isHot", value = "是否热门", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "isNew", value = "是否新品", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - }) + @Operation(summary = "修改商品") @PostMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) GoodsParam param, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); @@ -318,10 +243,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) GoodsParam param, } @MerchantPermission - @ApiOperation(value = "删除商品") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品表主键id", required = true, paramType = "query", dataType = "int"), - }) + @Operation(summary = "删除商品") @PostMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) Goods param, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); @@ -364,7 +286,7 @@ public BasicResult delete(@RequestBody @Validated(value = {}) Goods param, HttpS return basicResult; } -// @ApiOperation(value = "导入商品Excel报表") +// @Operation(summary = "导入商品Excel报表") // @PostMapping(value = "/import") // public BasicResult importGoods(@RequestParam(value = "file", required = true) MultipartFile file){ // BasicResult basicResult = new BasicResult(); @@ -407,12 +329,8 @@ public BasicResult delete(@RequestBody @Validated(value = {}) Goods param, HttpS // return basicResult; // } // -// @ApiOperation(value = "导出商品Excel报表") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), -// @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), -// }) -// @GetMapping(value = "/export") +// @Operation(summary = "导出商品Excel报表") +//// @GetMapping(value = "/export") // public void exportGoods(int pageNo, int pageSize, Goods goods, HttpServletResponse response){ // try { // // 生成Excel数据 @@ -442,12 +360,8 @@ public BasicResult delete(@RequestBody @Validated(value = {}) Goods param, HttpS // } // } -// @ApiOperation(value = "菜单状态修改(启用或禁用)") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "ids", value = "商品主键id集合(批量删除时id以逗号分隔)", required = true, paramType = "query", dataType = "String"), -// @ApiImplicitParam(name = "status", value = "是否启用 0-上架、1-下架", required = true, paramType = "query", dataType = "int") -// }) -// @DeleteMapping(value = "/update_status") +// @Operation(summary = "菜单状态修改(启用或禁用)") +//// @DeleteMapping(value = "/update_status") // public BasicResult updateStatus(List ids,Integer status){ // BasicResult basicResult = new BasicResult(); // @@ -459,10 +373,7 @@ public BasicResult delete(@RequestBody @Validated(value = {}) Goods param, HttpS // } - @ApiOperation(value = "获取单个商品详情信息") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品表主键id", required = true, paramType = "query", dataType = "int"), - }) + @Operation(summary = "获取单个商品详情信息") @PostMapping(value = "/getById") public BasicResult getById(@RequestBody @Validated(value = {}) Goods param, HttpServletRequest request){ BasicData basicResult = new BasicData(); @@ -497,38 +408,7 @@ public BasicResult getById(@RequestBody @Validated(value = {}) Goods param, Http } - /*@ApiOperation(value = "商品规格信息列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "商品名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "categoryId", value = "分类id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "categoryName", value = "分类名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "brandId", value = "品牌id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "brandName", value = "品牌名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "mainImage", value = "商品主图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "subImages", value = "商品子图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specList", value = "商品规格", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "detail", value = "商品详情", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "detailImages", value = "详情图片", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "一口价", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "salePrice", value = "折扣价", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "monthlySales", value = "月销量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "totalSales", value = "累计销量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "totalComments", value = "累计评价", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "stock", value = "库存", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isHot", value = "是否热门", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "isNew", value = "是否新品", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "specificationId", value = "规格id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "specificationName", value = "规格名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specificationOptionId", value = "商品规格选项id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "specificationOptionName", value = "商品规格选项名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specificationOptionPrice", value = "商品规格选项单价/加价金额", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "specificationOptionStock", value = "商品规格选项库存 1代表有货,0代表无货", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) - @PostMapping(value = "/listSpecification") + /*@Operation(summary = "商品规格信息列表")@PostMapping(value = "/listSpecification") public BasicResult listSpecification(int pageNo, int pageSize, GoodsSpecificationDto goodsSpecificationDto){ BasicData basicResult = new BasicData(); diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsRawmaterialRelationController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsRawmaterialRelationController.java index 698bdf1..f5e7caa 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsRawmaterialRelationController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsRawmaterialRelationController.java @@ -13,10 +13,16 @@ import com.siam.package_goods.service.GoodsRawmaterialRelationService; import com.siam.package_goods.entity.Rawmaterial; import com.siam.package_goods.service.RawmaterialService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -29,7 +35,7 @@ @RestController @RequestMapping(value = "/rest/merchant/goodsRawmaterialRelation") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端原料配比模块相关接口", description = "MerchantGoodsRawmaterialRelationController") +@Tag(name = "商家端原料配比模块相关接口", description = "MerchantGoodsRawmaterialRelationController") public class MerchantGoodsRawmaterialRelationController { @Autowired @@ -41,17 +47,7 @@ public class MerchantGoodsRawmaterialRelationController { @Autowired private GoodsService goodsService; - @ApiOperation(value = "原料配比列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "原料配比表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "原料配比名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "detail", value = "原料配比详情描述", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - }) - @PostMapping(value = "/list") + @Operation(summary = "原料配比列表")@PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) GoodsRawmaterialRelation goodsRawmaterialRelation){ BasicData basicResult = new BasicData(); Page page = goodsRawmaterialRelationService.getListByPage(goodsRawmaterialRelation.getPageNo(), goodsRawmaterialRelation.getPageSize(), goodsRawmaterialRelation); @@ -59,12 +55,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) GoodsRawmaterialRela return BasicResult.success(page); } - @ApiOperation(value = "设置原料配比") - @ApiImplicitParams({ - @ApiImplicitParam(name = "goodsListStr", value = "商品id", required = true, paramType = "query", dataType = "List"), - @ApiImplicitParam(name = "relationListStr", value = "原料", required = true, paramType = "query", dataType = "List"), - }) - @PostMapping(value = "/insert") + @Operation(summary = "设置原料配比")@PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) GoodsRawmaterialRelation param){ BasicResult basicResult = new BasicResult(); @@ -135,15 +126,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) GoodsRawmaterialRe } - @ApiOperation(value = "修改原料配比") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "原料配比主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "原料配比名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "detail", value = "原料配比详情描述", required = false, paramType = "query", dataType = "string") - }) - @PutMapping(value = "/update") + @Operation(summary = "修改原料配比")@PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) GoodsRawmaterialRelation goodsRawmaterialRelation){ BasicResult basicResult = new BasicResult(); @@ -157,11 +140,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) GoodsRawmaterialRe } - @ApiOperation(value = "删除原料配比") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "原料配比主键id", required = true, paramType = "query", dataType = "int") - }) - @DeleteMapping(value = "/delete") + @Operation(summary = "删除原料配比")@DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) GoodsRawmaterialRelation param){ BasicResult basicResult = new BasicResult(); @@ -181,27 +160,14 @@ public BasicResult delete(@RequestBody @Validated(value = {}) GoodsRawmaterialRe basicResult.setMessage("删除成功"); return basicResult; } - @ApiOperation(value = "查询原料配比信息") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "原料配比表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "goodsName", value = "商品名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - }) - @PostMapping(value = "/find/goodsRawmaterialRelation") + @Operation(summary = "查询原料配比信息")@PostMapping(value = "/find/goodsRawmaterialRelation") public BasicResult findGoodsRawmaterialRelation(@RequestBody @Validated(value = {}) GoodsRawmaterialRelation param){ BasicData basicResult = new BasicData(); Page page = goodsRawmaterialRelationService.findGoodsRawmaterialRelation(param.getPageNo(), param.getPageSize(), param.getGoodsName()); return BasicResult.success(page); } - @ApiOperation(value = "通过商品查询原料配比信息详情") - @ApiImplicitParams({ - @ApiImplicitParam(name = "goodsId", value = "商品id", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - }) - @PostMapping(value = "/find/goodsRawmaterialRelationByGoodsId") + @Operation(summary = "通过商品查询原料配比信息详情")@PostMapping(value = "/find/goodsRawmaterialRelationByGoodsId") public BasicResult findGoodsRawmaterialRelationByGoodsId(@RequestBody @Validated(value = {}) GoodsRawmaterialRelation param){ BasicData basicResult = new BasicData(); Page page = goodsRawmaterialRelationService.selectByGoodsId(param.getPageNo(), param.getPageSize(), param.getGoodsId()); diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsSpecificationController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsSpecificationController.java index 701b788..aad0db1 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsSpecificationController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsSpecificationController.java @@ -8,10 +8,11 @@ import com.siam.package_goods.entity.GoodsSpecification; import com.siam.package_goods.model.example.GoodsSpecificationExample; import com.siam.package_goods.service.GoodsSpecificationService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -23,22 +24,12 @@ @RestController @RequestMapping(value = "/rest/merchant/goodsSpecification") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端商品规格模块相关接口", description = "MerchantGoodsSpecificationController") +@Tag(name = "商家端商品规格模块相关接口", description = "MerchantGoodsSpecificationController") public class MerchantGoodsSpecificationController { @Autowired private GoodsSpecificationService goodsSpecificationService; - @ApiOperation(value = "商品规格列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品规格表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "goodsId", value = "商品id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "规格名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序号", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "goodsName", value = "商品名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsMainImage", value = "商品主图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) + @Operation(summary = "商品规格列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) GoodsSpecification goodsSpecification){ BasicData basicResult = new BasicData(); @@ -49,12 +40,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) GoodsSpecification g } @MerchantPermission - @ApiOperation(value = "修改商品规格") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品规格表主键id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "规格名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序号", required = true, paramType = "query", dataType = "int"), - }) + @Operation(summary = "修改商品规格") @PostMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) GoodsSpecification goodsSpecification){ BasicResult basicResult = new BasicResult(); @@ -87,13 +73,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) GoodsSpecification return basicResult; } - /*@ApiOperation(value = "新增商品规格") - @ApiImplicitParams({ - @ApiImplicitParam(name = "name", value = "规格名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序号", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - }) - @PostMapping(value = "/insert") + /*@Operation(summary = "新增商品规格")@PostMapping(value = "/insert") public BasicResult insert(Specification specification){ BasicResult basicResult = new BasicResult(); @@ -105,11 +85,7 @@ public BasicResult insert(Specification specification){ return basicResult; }*/ - /*@ApiOperation(value = "删除商品规格(含批量操作)") - @ApiImplicitParams({ - @ApiImplicitParam(name = "ids", value = "商品规格表主键id(批量删除时id以逗号分隔)", required = true, paramType = "query", dataType = "string"), - }) - @PostMapping(value = "/delete") + /*@Operation(summary = "删除商品规格(含批量操作)")@PostMapping(value = "/delete") public BasicResult delete(@RequestParam(value = "ids", required = true) List ids){ BasicResult basicResult = new BasicResult(); diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsSpecificationOptionController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsSpecificationOptionController.java index 503dd0d..eb8b826 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsSpecificationOptionController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantGoodsSpecificationOptionController.java @@ -13,10 +13,16 @@ import com.siam.package_goods.model.example.GoodsSpecificationOptionExample; import com.siam.package_goods.model.dto.GoodsSpecificationOptionDto; import com.siam.package_goods.service.GoodsSpecificationOptionService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -29,7 +35,7 @@ @RestController @RequestMapping(value = "/rest/merchant/goodsSpecificationOption") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端商品规格选项模块相关接口", description = "MerchantGoodsSpecificationOptionController") +@Tag(name = "商家端商品规格选项模块相关接口", description = "MerchantGoodsSpecificationOptionController") public class MerchantGoodsSpecificationOptionController { @Autowired private GoodsSpecificationOptionService goodsSpecificationOptionService; @@ -40,22 +46,7 @@ public class MerchantGoodsSpecificationOptionController { @Autowired private GoodsAccessoriesService goodsAccessoriesService; - @ApiOperation(value = "商品规格选项列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品规格选项表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "goodsId", value = "商品id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "specificationId", value = "规格id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "商品规格选项名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "单价/加价金额", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stock", value = "库存 1代表有货,0代表无货", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "sortNumber", value = "排序号", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "specificationName", value = "规格名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsName", value = "商品名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsMainImage", value = "商品主图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) - @PostMapping(value = "/list") + @Operation(summary = "商品规格选项列表")@PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) GoodsSpecificationOptionDto goodsSpecificationOptionDto){ BasicData basicResult = new BasicData(); @@ -64,15 +55,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) GoodsSpecificationOp return BasicResult.success(page); } - @ApiOperation(value = "添加商品规格选项") - @ApiImplicitParams({ - @ApiImplicitParam(name = "goodsId", value = "商品id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "商品规格选项名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "单价/加价金额", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stock", value = "库存 1代表有货,0代表无货", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "specificationName", value = "规格名称", required = true, paramType = "query", dataType = "string"), - }) - @PostMapping(value = "/insert") + @Operation(summary = "添加商品规格选项")@PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) GoodsSpecificationOptionDto goodsSpecificationOptionDto){ BasicData basicResult = new BasicData(); @@ -132,15 +115,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) GoodsSpecification } @MerchantPermission - @ApiOperation(value = "修改商品规格选项") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品规格选项表主键id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "商品规格选项名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "单价/加价金额", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stock", value = "库存 1代表有货,0代表无货", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "sortNumber", value = "排序号", required = true, paramType = "query", dataType = "int"), - }) - @PostMapping(value = "/update") + @Operation(summary = "修改商品规格选项")@PostMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) GoodsSpecificationOptionDto goodsSpecificationOptionDto){ BasicResult basicResult = new BasicResult(); @@ -204,11 +179,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) GoodsSpecification } @MerchantPermission - @ApiOperation(value = "删除商品规格选项(含批量操作)") - @ApiImplicitParams({ - @ApiImplicitParam(name = "ids", value = "商品规格选项表主键id(批量删除时id以逗号分隔)", required = true, paramType = "query", dataType = "string"), - }) - @PostMapping(value = "/delete") + @Operation(summary = "删除商品规格选项(含批量操作)")@PostMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) GoodsSpecificationOption param){ BasicResult basicResult = new BasicResult(); @@ -239,11 +210,7 @@ public BasicResult delete(@RequestBody @Validated(value = {}) GoodsSpecification return basicResult; } - /*@ApiOperation(value = "生成商品公共口味") - @ApiImplicitParams({ - @ApiImplicitParam(name = "goodsId", value = "商品id", required = true, paramType = "query", dataType = "int") - }) - @PostMapping(value = "/insertPublicSpecification") + /*@Operation(summary = "生成商品公共口味")@PostMapping(value = "/insertPublicSpecification") public BasicResult insertPublicSpecification(int goodsId){ BasicResult basicResult = new BasicResult(); diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantMenuController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantMenuController.java index 79a7d63..9ce4a23 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantMenuController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantMenuController.java @@ -13,22 +13,22 @@ import com.siam.package_merchant.auth.cache.MerchantSessionManager; import com.siam.package_merchant.entity.Merchant; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.Date; @RestController @RequestMapping(value = "/rest/merchant/menu") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端菜单分类模块相关接口", description = "MerchantMenuController") +@Tag(name = "商家端菜单分类模块相关接口", description = "MerchantMenuController") public class MerchantMenuController { @Autowired @@ -43,16 +43,7 @@ public class MerchantMenuController { @Autowired private MerchantSessionManager merchantSessionManager; - @ApiOperation(value = "菜单列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "商品名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "detail", value = "菜单分类详情描述", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - }) + @Operation(summary = "菜单列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) Menu menu, HttpServletRequest request){ BasicData basicResult = new BasicData(); @@ -66,14 +57,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) Menu menu, HttpServl return BasicResult.success(page); } - @ApiOperation(value = "菜单创建") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "菜单主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "菜单名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "detail", value = "菜单分类详情描述", required = false, paramType = "query", dataType = "string") - }) + @Operation(summary = "菜单创建") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) Menu menu, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); @@ -93,14 +77,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) Menu menu, HttpSer } @MerchantPermission - @ApiOperation(value = "菜单修改") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "菜单主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "菜单名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "detail", value = "菜单分类详情描述", required = false, paramType = "query", dataType = "string") - }) + @Operation(summary = "菜单修改") @PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) Menu menu, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); @@ -125,10 +102,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) Menu menu, HttpSer } @MerchantPermission - @ApiOperation(value = "菜单删除") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "菜单主键id集合(批量删除时id以逗号分隔)", required = true, paramType = "query", dataType = "String") - }) + @Operation(summary = "菜单删除") @DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) Menu param , HttpServletRequest request){ BasicResult basicResult = new BasicResult(); diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantRawmaterialController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantRawmaterialController.java index cf175a6..19ee6c7 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantRawmaterialController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantRawmaterialController.java @@ -8,10 +8,10 @@ import com.siam.package_goods.service.GoodsRawmaterialRelationService; import com.siam.package_goods.entity.Rawmaterial; import com.siam.package_goods.service.RawmaterialService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -22,7 +22,7 @@ @RestController @RequestMapping(value = "/rest/merchant/rawmaterial") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端原料模块相关接口", description = "MerchantRawmaterialController") +@Tag(name = "商家端原料模块相关接口", description = "MerchantRawmaterialController") public class MerchantRawmaterialController { @Autowired private RawmaterialService rawmaterialService; @@ -30,20 +30,7 @@ public class MerchantRawmaterialController { @Autowired private GoodsRawmaterialRelationService goodsRawmaterialRelationService; - @ApiOperation(value = "原料列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "原料表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "原料名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "mainImage", value = "原料主图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "description", value = "原料描述", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "unit", value = "采购单位", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "采购单价", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stock", value = "库存", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stockLowerLimit", value = "库存过低线/库存下限", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stockUpperLimit", value = "库存超出线/库存上限", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - }) + @Operation(summary = "原料列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) Rawmaterial rawmaterial){ BasicData basicResult = new BasicData(); @@ -52,17 +39,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) Rawmaterial rawmater return BasicResult.success(page); } - @ApiOperation(value = "新增原料") - @ApiImplicitParams({ - @ApiImplicitParam(name = "name", value = "原料名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "mainImage", value = "原料主图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "description", value = "原料描述", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "unit", value = "采购单位", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "采购单价", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stock", value = "库存", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stockLowerLimit", value = "库存过低线/库存下限", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stockUpperLimit", value = "库存超出线/库存上限", required = true, paramType = "query", dataType = "BigDecimal"), - }) + @Operation(summary = "新增原料") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) Rawmaterial rawmaterial){ BasicResult basicResult = new BasicResult(); @@ -78,18 +55,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) Rawmaterial rawmat } - @ApiOperation(value = "修改原料") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "原料主键id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "原料名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "mainImage", value = "原料主图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "description", value = "原料描述", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "unit", value = "采购单位", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "采购单价", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stock", value = "库存", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stockLowerLimit", value = "库存过低线/库存下限", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stockUpperLimit", value = "库存超出线/库存上限", required = true, paramType = "query", dataType = "BigDecimal"), - }) + @Operation(summary = "修改原料") @PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) Rawmaterial rawmaterial){ BasicResult basicResult = new BasicResult(); @@ -104,10 +70,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) Rawmaterial rawmat } - @ApiOperation(value = "删除原料") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "原料主键id", required = true, paramType = "query", dataType = "int") - }) + @Operation(summary = "删除原料") @DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) Rawmaterial param){ BasicResult basicResult = new BasicResult(); diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantRecommendGoodsController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantRecommendGoodsController.java index b05eca9..1b8b26b 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantRecommendGoodsController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantRecommendGoodsController.java @@ -12,14 +12,15 @@ import com.siam.package_goods.model.example.MerchantRecommendGoodsExample; import com.siam.package_goods.service.MerchantRecommendGoodsService; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.Date; import java.util.List; import java.util.Map; @@ -27,7 +28,7 @@ @RestController @RequestMapping(value = "/rest/merchant/merchantRecommendGoods") @Transactional(rollbackFor = Exception.class) - @Api(tags = "商家端商家推荐商品模块相关接口", description = "MerchantRecommendGoodsController") + @Tag(name = "商家端商家推荐商品模块相关接口", description = "MerchantRecommendGoodsController") public class MerchantRecommendGoodsController { @Autowired private MerchantRecommendGoodsService merchantRecommendGoodsService; @@ -38,7 +39,7 @@ public class MerchantRecommendGoodsController { @Autowired private MerchantSessionManager merchantSessionManager; - @ApiOperation(value = "商家推荐商品信息列表") + @Operation(summary = "商家推荐商品信息列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) MerchantRecommendGoods merchantRecommendGoods, HttpServletRequest request){ BasicData basicResult = new BasicData(); @@ -51,7 +52,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) MerchantRecommendGoo return BasicResult.success(page); } - @ApiOperation(value = "新增商家推荐商品信息") + @Operation(summary = "新增商家推荐商品信息") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) MerchantRecommendGoods param, HttpServletRequest request) { BasicResult basicResult = new BasicResult(); diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantStatisticsController.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantStatisticsController.java index 08326f3..dfa4fda 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantStatisticsController.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/controller/merchant/MerchantStatisticsController.java @@ -3,7 +3,8 @@ import com.siam.package_common.entity.BasicResult; import com.siam.package_goods.model.param.StatisticsParam; import com.siam.package_goods.service.StatisticsService; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -17,7 +18,7 @@ @RestController @RequestMapping(value = "/rest/merchant/statistics") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台统计模块相关接口", description = "AdminAdvertisementController") +@Tag(name = "后台统计模块相关接口", description = "AdminAdvertisementController") public class MerchantStatisticsController { @Autowired diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/feign/GoodsFeignProvider.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/feign/GoodsFeignProvider.java index 83664d9..2ee028e 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/feign/GoodsFeignProvider.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/feign/GoodsFeignProvider.java @@ -81,4 +81,15 @@ public BasicResult> selectByExample(GoodsParam param) { return BasicResult.success(goodsMapper.selectList(wrapper)); } + + @Override + public BasicResult decreaseStock(@RequestParam("id") Integer id, @RequestParam("number") Integer number) { + goodsService.decreaseStock(id, number); + return BasicResult.success(); + } + + @Override + public BasicResult increaseStock(@RequestParam("id") Integer id, @RequestParam("number") Integer number) { + goodsService.increaseStock(id, number); + return BasicResult.success(); } \ No newline at end of file diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/mapper/GoodsMapper.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/mapper/GoodsMapper.java index 0e166ec..64fe3c5 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/mapper/GoodsMapper.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/mapper/GoodsMapper.java @@ -132,6 +132,19 @@ public interface GoodsMapper extends BaseMapper { @Update("update tb_goods set total_sales=total_sales+#{num} where id=#{goodsId}") int updateTotalSales(@Param("goodsId") Integer goodsId,@Param("num") Integer num); + /** + * CAS 原子扣减库存:一条 SQL 完成 check-and-act,避免并发超卖 + * @return 受影响行数,0 表示库存不足 + */ + @Update("update tb_goods set stock = stock - #{number} where id = #{id} and stock >= #{number}") + int decreaseStockByCAS(@Param("id") Integer id, @Param("number") Integer number); + + /** + * CAS 原子增加库存:一条 SQL 完成 check-and-act,避免并发问题 + */ + @Update("update tb_goods set stock = stock + #{number} where id = #{id}") + int increaseStockByCAS(@Param("id") Integer id, @Param("number") Integer number); + @Update("update tb_goods set monthly_sales=0 ") int monthlySalesReset(); diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/service_impl/GoodsServiceImpl.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/service_impl/GoodsServiceImpl.java index 609f831..9481949 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/service_impl/GoodsServiceImpl.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/service_impl/GoodsServiceImpl.java @@ -84,25 +84,15 @@ public Page> getListByPageJoinSpecification(int pageNo, int @Override public void increaseStock(int id, int number) { - Goods dbGoods = goodsMapper.selectById(id); - //增加库存数量 - Goods updateGoods = new Goods(); - updateGoods.setId(dbGoods.getId()); - updateGoods.setStock(dbGoods.getStock() + number); - goodsMapper.updateById(updateGoods); + goodsMapper.increaseStockByCAS(id, number); } @Override public void decreaseStock(int id, int number) { - Goods dbGoods = goodsMapper.selectById(id); - if(dbGoods.getStock() - number < 0){ - throw new StoneCustomerException(dbGoods.getName() + "库存不足,请减少该单品购买数量"); + int rows = goodsMapper.decreaseStockByCAS(id, number); + if(rows == 0){ + throw new StoneCustomerException("手慢了,商品库存不足"); } - //减少库存数量 - Goods updateGoods = new Goods(); - updateGoods.setId(dbGoods.getId()); - updateGoods.setStock(dbGoods.getStock() - number); - goodsMapper.updateById(updateGoods); } /** diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/service_impl/StatisticsServiceImpl.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/service_impl/StatisticsServiceImpl.java index 28e7cd1..b77f6e0 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/service_impl/StatisticsServiceImpl.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/service_impl/StatisticsServiceImpl.java @@ -3,6 +3,7 @@ import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.siam.package_common.constant.Quantity; +import com.siam.package_common.entity.BasicResult; import com.siam.package_common.util.DateUtilsExtend; import com.siam.package_common.util.DateUtilsPlus; import com.siam.package_goods.entity.Goods; @@ -87,40 +88,38 @@ public Map todayStatisticByAdmin(StatisticsParam param) { //今日支付订单、今日支付金额、待完成订单、待处理退款 order.setStartTime(DateUtilsExtend.getDayBegin()); order.setEndTime(DateUtilsExtend.getDayEnd()); - int dayCountPaid = orderFeignApi.selectCountCompleted(order).getData(); - BigDecimal daySumActualPrice = orderFeignApi.selectSumActualPrice(order).getData(); - int unCompletedNum = orderFeignApi.selectCountUnCompleted(order).getData(); - int waitHandleRefundNum = orderFeignApi.selectCountWaitHandle(order).getData(); + int dayCountPaid = safeInt(orderFeignApi.selectCountCompleted(order)); + BigDecimal daySumActualPrice = safeBigDecimal(orderFeignApi.selectSumActualPrice(order)); + int unCompletedNum = safeInt(orderFeignApi.selectCountUnCompleted(order)); + int waitHandleRefundNum = safeInt(orderFeignApi.selectCountWaitHandle(order)); //总帐余额 = 累计进账 - 累计出账 - //今日进账 = 所有微信支付入口汇总的金额;退款金额不做计算;余额支付、积分支付这种不算 - //今日出账 = 佣金提现 + 商户提现 + 退款金额之类的所有由微信支出的汇总;余额和积分的支付也算 MemberTradeRecord memberTradeRecord = new MemberTradeRecord(); memberTradeRecord.setStartTime(DateUtilsExtend.getDayBegin()); memberTradeRecord.setEndTime(DateUtilsExtend.getDayEnd()); - BigDecimal daySumIncome = memberTradeRecordFeignApi.selectSumIncome(memberTradeRecord).getData(); - BigDecimal daySumExpense = memberTradeRecordFeignApi.selectSumExpense(memberTradeRecord).getData(); + BigDecimal daySumIncome = safeBigDecimal(memberTradeRecordFeignApi.selectSumIncome(memberTradeRecord)); + BigDecimal daySumExpense = safeBigDecimal(memberTradeRecordFeignApi.selectSumExpense(memberTradeRecord)); //退款金额--微信/支付宝 OrderRefund orderRefund = new OrderRefund(); orderRefund.setStartTime(DateUtilsExtend.getDayBegin()); orderRefund.setEndTime(DateUtilsExtend.getDayEnd()); - BigDecimal daySumRefundAmount = orderRefundFeignApi.selectSumRefundAmount(orderRefund).getData(); + BigDecimal daySumRefundAmount = safeBigDecimal(orderRefundFeignApi.selectSumRefundAmount(orderRefund)); daySumExpense = daySumExpense.add(daySumRefundAmount).setScale(2, BigDecimal.ROUND_HALF_UP); //退款金额--余额/积分 - BigDecimal daySumRefundAmountByPlatformCoin = orderRefundFeignApi.selectSumRefundAmountByPlatformCoin(orderRefund).getData(); + BigDecimal daySumRefundAmountByPlatformCoin = safeBigDecimal(orderRefundFeignApi.selectSumRefundAmountByPlatformCoin(orderRefund)); daySumExpense = daySumExpense.subtract(daySumRefundAmountByPlatformCoin).setScale(2, BigDecimal.ROUND_HALF_UP); memberTradeRecord.setStartTime(new Date("1970/1/1 00:00:00")); memberTradeRecord.setEndTime(new Date("2100/1/1 00:00:00")); - BigDecimal totalSumIncome = memberTradeRecordFeignApi.selectSumIncome(memberTradeRecord).getData(); - BigDecimal totalSumExpense = memberTradeRecordFeignApi.selectSumExpense(memberTradeRecord).getData(); + BigDecimal totalSumIncome = safeBigDecimal(memberTradeRecordFeignApi.selectSumIncome(memberTradeRecord)); + BigDecimal totalSumExpense = safeBigDecimal(memberTradeRecordFeignApi.selectSumExpense(memberTradeRecord)); //退款金额--微信/支付宝 orderRefund.setStartTime(new Date("1970/1/1 00:00:00")); orderRefund.setEndTime(new Date("2100/1/1 00:00:00")); - BigDecimal totalSumRefundAmount = orderRefundFeignApi.selectSumRefundAmount(orderRefund).getData(); + BigDecimal totalSumRefundAmount = safeBigDecimal(orderRefundFeignApi.selectSumRefundAmount(orderRefund)); totalSumExpense = totalSumExpense.add(totalSumRefundAmount); //退款金额--余额/积分 - BigDecimal totalSumRefundAmountByPlatformCoin = orderRefundFeignApi.selectSumRefundAmountByPlatformCoin(orderRefund).getData(); + BigDecimal totalSumRefundAmountByPlatformCoin = safeBigDecimal(orderRefundFeignApi.selectSumRefundAmountByPlatformCoin(orderRefund)); totalSumExpense = totalSumExpense.subtract(totalSumRefundAmountByPlatformCoin).setScale(2, BigDecimal.ROUND_HALF_UP); BigDecimal balance = totalSumIncome.subtract(totalSumExpense).setScale(2, BigDecimal.ROUND_HALF_UP); @@ -128,48 +127,44 @@ public Map todayStatisticByAdmin(StatisticsParam param) { //商品支付金额、配送费金额、退款金额、配送费退款金额 -- 针对于所有店铺、现金/余额都算 Map orderSumField = orderFeignApi.selectSumField(order).getData(); Map orderRefundSumField = orderRefundFeignApi.selectSumField(new OrderRefund()).getData(); - BigDecimal totalActualPrice = new BigDecimal((Double) orderSumField.get("totalActualPrice")); - BigDecimal totalDeliveryFee = new BigDecimal((Double) orderSumField.get("totalDeliveryFee")); - BigDecimal totalRefundAmount = new BigDecimal((Double) orderRefundSumField.get("totalRefundAmount")); - BigDecimal totalRefundDeliveryFee = new BigDecimal((Double) orderRefundSumField.get("totalRefundDeliveryFee")); + BigDecimal totalActualPrice = orderSumField != null && orderSumField.get("totalActualPrice") != null ? new BigDecimal((Double) orderSumField.get("totalActualPrice")) : BigDecimal.ZERO; + BigDecimal totalDeliveryFee = orderSumField != null && orderSumField.get("totalDeliveryFee") != null ? new BigDecimal((Double) orderSumField.get("totalDeliveryFee")) : BigDecimal.ZERO; + BigDecimal totalRefundAmount = orderRefundSumField != null && orderRefundSumField.get("totalRefundAmount") != null ? new BigDecimal((Double) orderRefundSumField.get("totalRefundAmount")) : BigDecimal.ZERO; + BigDecimal totalRefundDeliveryFee = orderRefundSumField != null && orderRefundSumField.get("totalRefundDeliveryFee") != null ? new BigDecimal((Double) orderRefundSumField.get("totalRefundDeliveryFee")) : BigDecimal.ZERO; //待处理开店申请、待处理提现申请、待处理变更资料申请、待处理退款申请 ShopParam shopParam = new ShopParam(); shopParam.setAuditStatus(Quantity.INT_1); - int handleShopCount = shopFeignApi.countByExample(shopParam).getData(); + int handleShopCount = safeInt(shopFeignApi.countByExample(shopParam)); - int handleMerchantWithdrawCount = merchantWithdrawRecordFeignApi.countByAuditStatus(Quantity.INT_1).getData(); + int handleMerchantWithdrawCount = safeInt(merchantWithdrawRecordFeignApi.countByAuditStatus(Quantity.INT_1)); ShopChangeRecordParam changeRecordParam = new ShopChangeRecordParam(); changeRecordParam.setAuditStatus(Quantity.INT_1); - int handleShopChangeCount = shopChangeRecordFeignApi.countByExample(changeRecordParam).getData(); + int handleShopChangeCount = safeInt(shopChangeRecordFeignApi.countByExample(changeRecordParam)); OrderRefund orderRefundCount = new OrderRefund(); orderRefundCount.setStatus(Quantity.INT_4); - int handleOrderRefundCount = orderRefundFeignApi.countByExample(orderRefundCount).getData(); + int handleOrderRefundCount = safeInt(orderRefundFeignApi.countByExample(orderRefundCount)); //商家总览:已下架、已上架、全部商家 shopParam = new ShopParam(); shopParam.setStatus(Quantity.INT_3); - int underShelfShopCount = shopFeignApi.countByExample(shopParam).getData(); + int underShelfShopCount = safeInt(shopFeignApi.countByExample(shopParam)); shopParam = new ShopParam(); shopParam.setStatus(Quantity.INT_2); - int onShelfShopCount = shopFeignApi.countByExample(shopParam).getData(); + int onShelfShopCount = safeInt(shopFeignApi.countByExample(shopParam)); - /*List filterList = new ArrayList<>(); - filterList.add(Quantity.INT_1); - filterList.add(Quantity.INT_2); - filterList.add(Quantity.INT_3);*/ shopParam = new ShopParam(); shopParam.setAuditStatus(Quantity.INT_2); - int allShopCount = shopFeignApi.countByExample(shopParam).getData(); + int allShopCount = safeInt(shopFeignApi.countByExample(shopParam)); //用户总览:今日新增、昨日新增、本月新增、会员总数 - int dayMemberCount = memberFeignApi.selectCountRegister(DateUtilsExtend.getDayBegin(), DateUtilsExtend.getDayEnd()).getData(); - int yesterdayMemberCount = memberFeignApi.selectCountRegister(DateUtilsExtend.getBeginDayOfYesterday(), DateUtilsExtend.getEndDayOfYesterDay()).getData(); - int thisMonthMemberCount = memberFeignApi.selectCountRegister(DateUtilsExtend.getBeginDayOfMonth(), DateUtilsExtend.getEndDayOfMonth()).getData(); - int allMemberCount = memberFeignApi.countByExample(new Member()).getData(); + int dayMemberCount = safeInt(memberFeignApi.selectCountRegister(DateUtilsExtend.getDayBegin(), DateUtilsExtend.getDayEnd())); + int yesterdayMemberCount = safeInt(memberFeignApi.selectCountRegister(DateUtilsExtend.getBeginDayOfYesterday(), DateUtilsExtend.getEndDayOfYesterDay())); + int thisMonthMemberCount = safeInt(memberFeignApi.selectCountRegister(DateUtilsExtend.getBeginDayOfMonth(), DateUtilsExtend.getEndDayOfMonth())); + int allMemberCount = safeInt(memberFeignApi.countByExample(new Member())); resultMap.put("dayCountPaid", dayCountPaid); resultMap.put("daySumActualPrice", daySumActualPrice); @@ -264,55 +259,55 @@ public Map todayStatisticByMerchant(StatisticsParam param) { order.setEndTime(DateUtilsExtend.getDayEnd()); //今日支付订单、今日实际收入、今日进店人数、今日加购商品 log.debug("\n\n》》》 StatisticsServiceImpl.todayStatisticByMerchant - order = " + JSON.toJSONString(order)); - int dayCountPaid = orderFeignApi.selectCountCompleted(order).getData(); - BigDecimal daySumMerchantIncome = orderFeignApi.selectSumMerchantIncome(order).getData(); - int todayCountIntoShop = systemUsageRecordFeignApi.selectCountIntoShop(loginMerchant.getShopId(), DateUtilsExtend.getDayBegin(), DateUtilsExtend.getDayEnd()).getData(); + int dayCountPaid = safeInt(orderFeignApi.selectCountCompleted(order)); + BigDecimal daySumMerchantIncome = safeBigDecimal(orderFeignApi.selectSumMerchantIncome(order)); + int todayCountIntoShop = safeInt(systemUsageRecordFeignApi.selectCountIntoShop(loginMerchant.getShopId(), DateUtilsExtend.getDayBegin(), DateUtilsExtend.getDayEnd())); int todayCountShoppingCartGoodsNumber = shoppingCartService.selectCountGoodsNumber(loginMerchant.getShopId(), DateUtilsExtend.getDayBegin(), DateUtilsExtend.getDayEnd()); //待制作订单(自取)、待配送订单(外卖)、已完成订单、待处理退款申请 order.setShopId(loginMerchant.getShopId()); order.setStatus(Quantity.INT_2); - int waitHandleOrderCount = orderFeignApi.countByExample(order).getData(); + int waitHandleOrderCount = safeInt(orderFeignApi.countByExample(order)); order.setShopId(loginMerchant.getShopId()); order.setStatus(Quantity.INT_4); - int waitDeliverOrderCount = orderFeignApi.countByExample(order).getData(); + int waitDeliverOrderCount = safeInt(orderFeignApi.countByExample(order)); order.setShopId(loginMerchant.getShopId()); order.setStatus(Quantity.INT_6); - int completedOrderCount = orderFeignApi.countByExample(order).getData(); + int completedOrderCount = safeInt(orderFeignApi.countByExample(order)); order.setShopId(loginMerchant.getShopId()); order.setStatus(Quantity.INT_7); - int handleOrderRefundCount = orderFeignApi.countByExample(order).getData(); + int handleOrderRefundCount = safeInt(orderFeignApi.countByExample(order)); //商品总览:已下架、已上架、库存售罄、全部商品 LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Goods::getShopId, loginMerchant.getShopId()); wrapper.eq(Goods::getStatus, Quantity.INT_3); - int underShelfGoodsCount = goodsService.count(wrapper); + long underShelfGoodsCount = goodsService.count(wrapper); wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Goods::getShopId, loginMerchant.getShopId()); wrapper.eq(Goods::getStatus, Quantity.INT_2); - int onShelfGoodsCount = goodsService.count(wrapper); + long onShelfGoodsCount = goodsService.count(wrapper); wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Goods::getShopId, loginMerchant.getShopId()); wrapper.eq(Goods::getStatus, Quantity.INT_4); - int sellOutGoodsCount = goodsService.count(wrapper); + long sellOutGoodsCount = goodsService.count(wrapper); wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Goods::getShopId, loginMerchant.getShopId()); - int allGoodsCount = goodsService.count(wrapper); + long allGoodsCount = goodsService.count(wrapper); //指数总览:客单价(成交金额/成交订单数)、下单转化率(下单人数/访问人数)、下单-支付转化率(支付人数/下单人数)、支付转化率(支付人数/访问人数) Date startDate = new Date("1970/1/1 00:00:00"); BigDecimal perCustomerTransaction; order.setStartTime(startDate); order.setEndTime(DateUtilsExtend.getDayEnd()); - BigDecimal sumActualPrice = orderFeignApi.selectSumActualPrice(order).getData(); - int countPaid = orderFeignApi.selectCountCompleted(order).getData(); + BigDecimal sumActualPrice = safeBigDecimal(orderFeignApi.selectSumActualPrice(order)); + int countPaid = safeInt(orderFeignApi.selectCountCompleted(order)); if(countPaid == 0){ perCustomerTransaction = BigDecimal.valueOf(-1); }else{ @@ -322,8 +317,8 @@ public Map todayStatisticByMerchant(StatisticsParam param) { BigDecimal orderConversionRate; order.setStartTime(startDate); order.setEndTime(DateUtilsExtend.getDayEnd()); - int countOrderPeoples = orderFeignApi.selectCountOrderPeoples(order).getData(); - int countIntoShop = systemUsageRecordFeignApi.selectCountIntoShop(loginMerchant.getShopId(), startDate, DateUtilsExtend.getDayEnd()).getData(); + int countOrderPeoples = safeInt(orderFeignApi.selectCountOrderPeoples(order)); + int countIntoShop = safeInt(systemUsageRecordFeignApi.selectCountIntoShop(loginMerchant.getShopId(), startDate, DateUtilsExtend.getDayEnd())); if(countIntoShop == 0){ orderConversionRate = BigDecimal.valueOf(-1); }else{ @@ -333,7 +328,7 @@ public Map todayStatisticByMerchant(StatisticsParam param) { BigDecimal orderPaymentConversionRate; order.setStartTime(startDate); order.setEndTime(DateUtilsExtend.getDayEnd()); - int countPayers = orderFeignApi.selectCountPayers(order).getData(); + int countPayers = safeInt(orderFeignApi.selectCountPayers(order)); if(countOrderPeoples == 0){ orderPaymentConversionRate = BigDecimal.valueOf(-1); }else{ @@ -420,27 +415,27 @@ public Map todayStatisticByMerchant(StatisticsParam param) { order.setShopId(loginMerchant.getShopId()); //今日进店人数 - todayCountIntoShop = systemUsageRecordFeignApi.selectCountIntoShop(loginMerchant.getShopId(), today_startTime, today_endTime).getData(); + todayCountIntoShop = safeInt(systemUsageRecordFeignApi.selectCountIntoShop(loginMerchant.getShopId(), today_startTime, today_endTime)); //昨日进店人数 - int yesterdayCountIntoShop = systemUsageRecordFeignApi.selectCountIntoShop(loginMerchant.getShopId(), yesterday_startTime, yesterday_endTime).getData(); + int yesterdayCountIntoShop = safeInt(systemUsageRecordFeignApi.selectCountIntoShop(loginMerchant.getShopId(), yesterday_startTime, yesterday_endTime)); //今日支付金额(商家实际到手金额) order.setStartTime(today_startTime); order.setEndTime(today_endTime); - BigDecimal todaySumMerchantIncome = orderFeignApi.selectSumMerchantIncome(order).getData(); + BigDecimal todaySumMerchantIncome = safeBigDecimal(orderFeignApi.selectSumMerchantIncome(order)); //昨日支付金额(商家实际到手金额) order.setStartTime(yesterday_startTime); order.setEndTime(yesterday_endTime); - BigDecimal yesterdaySumMerchantIncome = orderFeignApi.selectSumMerchantIncome(order).getData(); + BigDecimal yesterdaySumMerchantIncome = safeBigDecimal(orderFeignApi.selectSumMerchantIncome(order)); //今日支付订单数量 order.setStartTime(today_startTime); order.setEndTime(today_endTime); - int todayCountPaid = orderFeignApi.selectCountCompleted(order).getData(); + int todayCountPaid = safeInt(orderFeignApi.selectCountCompleted(order)); //昨日支付订单数量 order.setStartTime(yesterday_startTime); order.setEndTime(yesterday_endTime); - int yesterdayCountPaid = orderFeignApi.selectCountCompleted(order).getData(); + int yesterdayCountPaid = safeInt(orderFeignApi.selectCountCompleted(order)); //今日加购商品数量 int todayCountGoodsNumber = shoppingCartService.selectCountGoodsNumber(loginMerchant.getShopId(), today_startTime, today_endTime); @@ -458,4 +453,28 @@ public Map todayStatisticByMerchant(StatisticsParam param) { return resultMap; } + + private int safeInt(BasicResult result) { + if (result == null || result.getData() == null) { + return 0; + } + return result.getData(); + } + + private BigDecimal safeBigDecimal(BasicResult result) { + if (result == null || result.getData() == null) { + return BigDecimal.ZERO; + } + Object data = result.getData(); + if (data instanceof BigDecimal) { + return (BigDecimal) data; + } + if (data instanceof Double) { + return BigDecimal.valueOf((Double) data); + } + if (data instanceof Number) { + return BigDecimal.valueOf(((Number) data).doubleValue()); + } + return BigDecimal.ZERO; + } } \ No newline at end of file diff --git a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/service_impl/internal/PointsMallStatisticsServiceImpl.java b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/service_impl/internal/PointsMallStatisticsServiceImpl.java index fd8c868..92eda39 100644 --- a/siam-goods/goods-provider/src/main/java/com/siam/package_goods/service_impl/internal/PointsMallStatisticsServiceImpl.java +++ b/siam-goods/goods-provider/src/main/java/com/siam/package_goods/service_impl/internal/PointsMallStatisticsServiceImpl.java @@ -1,6 +1,7 @@ package com.siam.package_goods.service_impl.internal; import com.siam.package_common.constant.Quantity; +import com.siam.package_common.entity.BasicResult; import com.siam.package_common.util.DateUtilsExtend; import com.siam.package_goods.model.param.StatisticsParam; import com.siam.package_goods.service.internal.PointsMallStatisticsService; @@ -85,10 +86,10 @@ public Map todayStatisticWithPointsMallByAdmin(StatisticsParam param) { //今日支付订单、今日支付金额、待完成订单、待处理退款 order.setStartTime(DateUtilsExtend.getDayBegin()); order.setEndTime(DateUtilsExtend.getDayEnd()); - int dayCountPaid = orderFeignApi.selectCountCompleted(order).getData(); - BigDecimal daySumActualPrice = orderFeignApi.selectSumActualPrice(order).getData(); - int unCompletedNum = orderFeignApi.selectCountUnCompleted(order).getData(); - int waitHandleRefundNum = orderFeignApi.selectCountWaitHandle(order).getData(); + int dayCountPaid = safeInt(orderFeignApi.selectCountCompleted(order)); + BigDecimal daySumActualPrice = safeBigDecimal(orderFeignApi.selectSumActualPrice(order)); + int unCompletedNum = safeInt(orderFeignApi.selectCountUnCompleted(order)); + int waitHandleRefundNum = safeInt(orderFeignApi.selectCountWaitHandle(order)); //总帐余额 = 累计进账 - 累计出账 //今日进账 = 所有微信支付入口汇总的金额;退款金额不做计算;余额支付、积分支付这种不算 @@ -96,38 +97,38 @@ public Map todayStatisticWithPointsMallByAdmin(StatisticsParam param) { MemberTradeRecord memberTradeRecord = new MemberTradeRecord(); memberTradeRecord.setStartTime(DateUtilsExtend.getDayBegin()); memberTradeRecord.setEndTime(DateUtilsExtend.getDayEnd()); - BigDecimal daySumIncome = memberTradeRecordFeignApi.selectSumIncome(memberTradeRecord).getData(); - BigDecimal daySumExpense = memberTradeRecordFeignApi.selectSumExpense(memberTradeRecord).getData(); + BigDecimal daySumIncome = safeBigDecimal(memberTradeRecordFeignApi.selectSumIncome(memberTradeRecord)); + BigDecimal daySumExpense = safeBigDecimal(memberTradeRecordFeignApi.selectSumExpense(memberTradeRecord)); //退款金额--微信/支付宝 OrderRefund orderRefund = new OrderRefund(); orderRefund.setStartTime(DateUtilsExtend.getDayBegin()); orderRefund.setEndTime(DateUtilsExtend.getDayEnd()); - BigDecimal daySumRefundAmount = orderRefundFeignApi.selectSumRefundAmount(orderRefund).getData(); + BigDecimal daySumRefundAmount = safeBigDecimal(orderRefundFeignApi.selectSumRefundAmount(orderRefund)); PointsMallOrderRefund pointsMallOrderRefund = new PointsMallOrderRefund(); pointsMallOrderRefund.setStartTime(DateUtilsExtend.getDayBegin()); pointsMallOrderRefund.setEndTime(DateUtilsExtend.getDayEnd()); - BigDecimal daySumRefundAmount_mall = pointsMallOrderRefundFeignApi.selectSumRefundAmount(pointsMallOrderRefund).getData(); + BigDecimal daySumRefundAmount_mall = safeBigDecimal(pointsMallOrderRefundFeignApi.selectSumRefundAmount(pointsMallOrderRefund)); daySumExpense = daySumExpense.add(daySumRefundAmount).add(daySumRefundAmount_mall).setScale(2, BigDecimal.ROUND_HALF_UP); //退款金额--余额/积分 - BigDecimal daySumRefundAmountByPlatformCoin = orderRefundFeignApi.selectSumRefundAmountByPlatformCoin(orderRefund).getData(); - BigDecimal daySumRefundAmountByPlatformCoin_mall = pointsMallOrderRefundFeignApi.selectSumRefundAmountByPlatformCoin(pointsMallOrderRefund).getData(); + BigDecimal daySumRefundAmountByPlatformCoin = safeBigDecimal(orderRefundFeignApi.selectSumRefundAmountByPlatformCoin(orderRefund)); + BigDecimal daySumRefundAmountByPlatformCoin_mall = safeBigDecimal(pointsMallOrderRefundFeignApi.selectSumRefundAmountByPlatformCoin(pointsMallOrderRefund)); daySumExpense = daySumExpense.subtract(daySumRefundAmountByPlatformCoin).subtract(daySumRefundAmountByPlatformCoin_mall).setScale(2, BigDecimal.ROUND_HALF_UP); memberTradeRecord.setStartTime(new Date("1970/1/1 00:00:00")); memberTradeRecord.setEndTime(new Date("2100/1/1 00:00:00")); - BigDecimal totalSumIncome = memberTradeRecordFeignApi.selectSumIncome(memberTradeRecord).getData(); - BigDecimal totalSumExpense = memberTradeRecordFeignApi.selectSumExpense(memberTradeRecord).getData(); + BigDecimal totalSumIncome = safeBigDecimal(memberTradeRecordFeignApi.selectSumIncome(memberTradeRecord)); + BigDecimal totalSumExpense = safeBigDecimal(memberTradeRecordFeignApi.selectSumExpense(memberTradeRecord)); //退款金额--微信/支付宝 orderRefund.setStartTime(new Date("1970/1/1 00:00:00")); orderRefund.setEndTime(new Date("2100/1/1 00:00:00")); - BigDecimal totalSumRefundAmount = orderRefundFeignApi.selectSumRefundAmount(orderRefund).getData(); + BigDecimal totalSumRefundAmount = safeBigDecimal(orderRefundFeignApi.selectSumRefundAmount(orderRefund)); pointsMallOrderRefund.setStartTime(new Date("1970/1/1 00:00:00")); pointsMallOrderRefund.setEndTime(new Date("2100/1/1 00:00:00")); - BigDecimal totalSumRefundAmount_mall = pointsMallOrderRefundFeignApi.selectSumRefundAmount(pointsMallOrderRefund).getData(); + BigDecimal totalSumRefundAmount_mall = safeBigDecimal(pointsMallOrderRefundFeignApi.selectSumRefundAmount(pointsMallOrderRefund)); totalSumExpense = totalSumExpense.add(totalSumRefundAmount).add(totalSumRefundAmount_mall); //退款金额--余额/积分 - BigDecimal totalSumRefundAmountByPlatformCoin = orderRefundFeignApi.selectSumRefundAmountByPlatformCoin(orderRefund).getData(); - BigDecimal totalSumRefundAmountByPlatformCoin_mall = pointsMallOrderRefundFeignApi.selectSumRefundAmountByPlatformCoin(pointsMallOrderRefund).getData(); + BigDecimal totalSumRefundAmountByPlatformCoin = safeBigDecimal(orderRefundFeignApi.selectSumRefundAmountByPlatformCoin(orderRefund)); + BigDecimal totalSumRefundAmountByPlatformCoin_mall = safeBigDecimal(pointsMallOrderRefundFeignApi.selectSumRefundAmountByPlatformCoin(pointsMallOrderRefund)); totalSumExpense = totalSumExpense.subtract(totalSumRefundAmountByPlatformCoin).subtract(totalSumRefundAmountByPlatformCoin_mall).setScale(2, BigDecimal.ROUND_HALF_UP); BigDecimal balance = totalSumIncome.subtract(totalSumExpense).setScale(2, BigDecimal.ROUND_HALF_UP); @@ -135,48 +136,44 @@ public Map todayStatisticWithPointsMallByAdmin(StatisticsParam param) { //商品支付金额、配送费金额、退款金额、配送费退款金额 -- 针对于所有店铺、现金/余额都算 Map orderSumField = orderFeignApi.selectSumField(order).getData(); Map orderRefundSumField = orderRefundFeignApi.selectSumField(new OrderRefund()).getData(); - BigDecimal totalActualPrice = new BigDecimal((Double) orderSumField.get("totalActualPrice")); - BigDecimal totalDeliveryFee = new BigDecimal((Double) orderSumField.get("totalDeliveryFee")); - BigDecimal totalRefundAmount = new BigDecimal((Double) orderRefundSumField.get("totalRefundAmount")); - BigDecimal totalRefundDeliveryFee = new BigDecimal((Double) orderRefundSumField.get("totalRefundDeliveryFee")); + BigDecimal totalActualPrice = orderSumField != null && orderSumField.get("totalActualPrice") != null ? new BigDecimal((Double) orderSumField.get("totalActualPrice")) : BigDecimal.ZERO; + BigDecimal totalDeliveryFee = orderSumField != null && orderSumField.get("totalDeliveryFee") != null ? new BigDecimal((Double) orderSumField.get("totalDeliveryFee")) : BigDecimal.ZERO; + BigDecimal totalRefundAmount = orderRefundSumField != null && orderRefundSumField.get("totalRefundAmount") != null ? new BigDecimal((Double) orderRefundSumField.get("totalRefundAmount")) : BigDecimal.ZERO; + BigDecimal totalRefundDeliveryFee = orderRefundSumField != null && orderRefundSumField.get("totalRefundDeliveryFee") != null ? new BigDecimal((Double) orderRefundSumField.get("totalRefundDeliveryFee")) : BigDecimal.ZERO; //待处理开店申请、待处理提现申请、待处理变更资料申请、待处理退款申请 ShopParam shopParam = new ShopParam(); shopParam.setAuditStatus(Quantity.INT_1); - int handleShopCount = shopFeignApi.countByExample(shopParam).getData(); + int handleShopCount = safeInt(shopFeignApi.countByExample(shopParam)); - int handleMerchantWithdrawCount = merchantWithdrawRecordFeignApi.countByAuditStatus(Quantity.INT_1).getData(); + int handleMerchantWithdrawCount = safeInt(merchantWithdrawRecordFeignApi.countByAuditStatus(Quantity.INT_1)); ShopChangeRecordParam changeRecordParam = new ShopChangeRecordParam(); changeRecordParam.setAuditStatus(Quantity.INT_1); - int handleShopChangeCount = shopChangeRecordFeignApi.countByExample(changeRecordParam).getData(); + int handleShopChangeCount = safeInt(shopChangeRecordFeignApi.countByExample(changeRecordParam)); OrderRefund orderRefundCount = new OrderRefund(); orderRefundCount.setStatus(Quantity.INT_4); - int handleOrderRefundCount = orderRefundFeignApi.countByExample(orderRefundCount).getData(); + int handleOrderRefundCount = safeInt(orderRefundFeignApi.countByExample(orderRefundCount)); //商家总览:已下架、已上架、全部商家 shopParam = new ShopParam(); shopParam.setStatus(Quantity.INT_3); - int underShelfShopCount = shopFeignApi.countByExample(shopParam).getData(); + int underShelfShopCount = safeInt(shopFeignApi.countByExample(shopParam)); shopParam = new ShopParam(); shopParam.setStatus(Quantity.INT_2); - int onShelfShopCount = shopFeignApi.countByExample(shopParam).getData(); + int onShelfShopCount = safeInt(shopFeignApi.countByExample(shopParam)); - /*List filterList = new ArrayList<>(); - filterList.add(Quantity.INT_1); - filterList.add(Quantity.INT_2); - filterList.add(Quantity.INT_3);*/ shopParam = new ShopParam(); shopParam.setAuditStatus(Quantity.INT_2); - int allShopCount = shopFeignApi.countByExample(shopParam).getData(); + int allShopCount = safeInt(shopFeignApi.countByExample(shopParam)); //用户总览:今日新增、昨日新增、本月新增、会员总数 - int dayMemberCount = memberFeignApi.selectCountRegister(DateUtilsExtend.getDayBegin(), DateUtilsExtend.getDayEnd()).getData(); - int yesterdayMemberCount = memberFeignApi.selectCountRegister(DateUtilsExtend.getBeginDayOfYesterday(), DateUtilsExtend.getEndDayOfYesterDay()).getData(); - int thisMonthMemberCount = memberFeignApi.selectCountRegister(DateUtilsExtend.getBeginDayOfMonth(), DateUtilsExtend.getEndDayOfMonth()).getData(); - int allMemberCount = memberFeignApi.countByExample(new Member()).getData(); + int dayMemberCount = safeInt(memberFeignApi.selectCountRegister(DateUtilsExtend.getDayBegin(), DateUtilsExtend.getDayEnd())); + int yesterdayMemberCount = safeInt(memberFeignApi.selectCountRegister(DateUtilsExtend.getBeginDayOfYesterday(), DateUtilsExtend.getEndDayOfYesterDay())); + int thisMonthMemberCount = safeInt(memberFeignApi.selectCountRegister(DateUtilsExtend.getBeginDayOfMonth(), DateUtilsExtend.getEndDayOfMonth())); + int allMemberCount = safeInt(memberFeignApi.countByExample(new Member())); resultMap.put("dayCountPaid", dayCountPaid); resultMap.put("daySumActualPrice", daySumActualPrice); @@ -269,45 +266,45 @@ public Map pointsMallTodayStatisticByAdmin(StatisticsParam param) { //今日支付订单、今日实际收入、今日进店人数、今日加购商品 order.setStartTime(DateUtilsExtend.getDayBegin()); order.setEndTime(DateUtilsExtend.getDayEnd()); - int dayCountPaid = pointsMallOrderFeignApi.selectCountCompleted(order).getData(); - BigDecimal daySumMerchantIncome = pointsMallOrderFeignApi.selectSumActualPrice(order).getData(); - int todayCountIntoShop = systemUsageRecordFeignApi.selectCountIntoPointsMall(DateUtilsExtend.getDayBegin(), DateUtilsExtend.getDayEnd()).getData(); - int todayCountShoppingCartGoodsNumber = pointsMallShoppingCartFeignApi.selectCountGoodsNumber(null, DateUtilsExtend.getDayBegin(), DateUtilsExtend.getDayEnd()).getData(); + int dayCountPaid = safeInt(pointsMallOrderFeignApi.selectCountCompleted(order)); + BigDecimal daySumMerchantIncome = safeBigDecimal(pointsMallOrderFeignApi.selectSumActualPrice(order)); + int todayCountIntoShop = safeInt(systemUsageRecordFeignApi.selectCountIntoPointsMall(DateUtilsExtend.getDayBegin(), DateUtilsExtend.getDayEnd())); + int todayCountShoppingCartGoodsNumber = safeInt(pointsMallShoppingCartFeignApi.selectCountGoodsNumber(null, DateUtilsExtend.getDayBegin(), DateUtilsExtend.getDayEnd())); //待配送订单(外卖)、已完成订单、待处理退款申请 PointsMallOrderParam pointsMallOrderParam = new PointsMallOrderParam(); pointsMallOrderParam.setStatus(Quantity.INT_4); - int waitDeliverOrderCount = pointsMallOrderFeignApi.countByExample(pointsMallOrderParam).getData(); + int waitDeliverOrderCount = safeInt(pointsMallOrderFeignApi.countByExample(pointsMallOrderParam)); pointsMallOrderParam.setStatus(Quantity.INT_6); - int completedOrderCount = pointsMallOrderFeignApi.countByExample(pointsMallOrderParam).getData(); + int completedOrderCount = safeInt(pointsMallOrderFeignApi.countByExample(pointsMallOrderParam)); pointsMallOrderParam.setStatus(Quantity.INT_7); - int handleOrderRefundCount = pointsMallOrderFeignApi.countByExample(pointsMallOrderParam).getData(); + int handleOrderRefundCount = safeInt(pointsMallOrderFeignApi.countByExample(pointsMallOrderParam)); //商品总览:已下架、已上架、库存售罄、全部商品 PointsMallGoodsParam goodsExample = new PointsMallGoodsParam(); goodsExample.setStatus(Quantity.INT_3); - int underShelfGoodsCount = pointsMallGoodsFeignApi.countByExample(goodsExample).getData(); + int underShelfGoodsCount = safeInt(pointsMallGoodsFeignApi.countByExample(goodsExample)); goodsExample = new PointsMallGoodsParam(); goodsExample.setStatus(Quantity.INT_2); - int onShelfGoodsCount = pointsMallGoodsFeignApi.countByExample(goodsExample).getData(); + int onShelfGoodsCount = safeInt(pointsMallGoodsFeignApi.countByExample(goodsExample)); goodsExample = new PointsMallGoodsParam(); goodsExample.setStatus(Quantity.INT_4); - int sellOutGoodsCount = pointsMallGoodsFeignApi.countByExample(goodsExample).getData(); + int sellOutGoodsCount = safeInt(pointsMallGoodsFeignApi.countByExample(goodsExample)); goodsExample = new PointsMallGoodsParam(); - int allGoodsCount = pointsMallGoodsFeignApi.countByExample(goodsExample).getData(); + int allGoodsCount = safeInt(pointsMallGoodsFeignApi.countByExample(goodsExample)); //指数总览:客单价(成交金额/成交订单数)、下单转化率(下单人数/访问人数)、下单-支付转化率(支付人数/下单人数)、支付转化率(支付人数/访问人数) Date startDate = new Date("1970/1/1 00:00:00"); BigDecimal perCustomerTransaction; order.setStartTime(startDate); order.setEndTime(DateUtilsExtend.getDayEnd()); - BigDecimal sumActualPrice = pointsMallOrderFeignApi.selectSumActualPrice(order).getData(); - int countPaid = pointsMallOrderFeignApi.selectCountCompleted(order).getData(); + BigDecimal sumActualPrice = safeBigDecimal(pointsMallOrderFeignApi.selectSumActualPrice(order)); + int countPaid = safeInt(pointsMallOrderFeignApi.selectCountCompleted(order)); if(countPaid == 0){ perCustomerTransaction = BigDecimal.valueOf(-1); }else{ @@ -315,8 +312,8 @@ public Map pointsMallTodayStatisticByAdmin(StatisticsParam param) { } BigDecimal orderConversionRate; - int countOrderPeoples = pointsMallOrderFeignApi.selectCountOrderPeoples(order).getData(); - int countIntoShop = systemUsageRecordFeignApi.selectCountIntoShop(null, startDate, DateUtilsExtend.getDayEnd()).getData(); + int countOrderPeoples = safeInt(pointsMallOrderFeignApi.selectCountOrderPeoples(order)); + int countIntoShop = safeInt(systemUsageRecordFeignApi.selectCountIntoShop(null, startDate, DateUtilsExtend.getDayEnd())); if(countIntoShop == 0){ orderConversionRate = BigDecimal.valueOf(-1); }else{ @@ -324,7 +321,7 @@ public Map pointsMallTodayStatisticByAdmin(StatisticsParam param) { } BigDecimal orderPaymentConversionRate; - int countPayers = pointsMallOrderFeignApi.selectCountPayers(order).getData(); + int countPayers = safeInt(pointsMallOrderFeignApi.selectCountPayers(order)); if(countOrderPeoples == 0){ orderPaymentConversionRate = BigDecimal.valueOf(-1); }else{ @@ -373,4 +370,28 @@ public Map pointsMallTodayStatisticByAdmin(StatisticsParam param) { return resultMap; } + + private int safeInt(BasicResult result) { + if (result == null || result.getData() == null) { + return 0; + } + return result.getData(); + } + + private BigDecimal safeBigDecimal(BasicResult result) { + if (result == null || result.getData() == null) { + return BigDecimal.ZERO; + } + Object data = result.getData(); + if (data instanceof BigDecimal) { + return (BigDecimal) data; + } + if (data instanceof Double) { + return BigDecimal.valueOf((Double) data); + } + if (data instanceof Number) { + return BigDecimal.valueOf(((Number) data).doubleValue()); + } + return BigDecimal.ZERO; + } } \ No newline at end of file diff --git a/siam-goods/goods-provider/src/main/resources/application-local.yml b/siam-goods/goods-provider/src/main/resources/application-local.yml index 4843526..af45b08 100644 --- a/siam-goods/goods-provider/src/main/resources/application-local.yml +++ b/siam-goods/goods-provider/src/main/resources/application-local.yml @@ -5,9 +5,9 @@ server: spring: #mysql datasource: - url: jdbc:mysql://127.0.0.1:3306/siam_cloud?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8 + url: jdbc:mysql://127.0.0.1:3306/siam_cloud?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true username: root - password: root + password: 123456 # #mongodb(默认时没有账号密码的) # # application: @@ -75,6 +75,18 @@ spring: application: name: goods-siam + # Nacos注册中心/配置中心 + cloud: + nacos: + discovery: + server-addr: 127.0.0.1:8848 + config: + server-addr: 127.0.0.1:8848 + file-extension: yaml + config: + import: + - optional:nacos:${spring.application.name}-local.yaml + #配置文件上传大小限制 servlet: multipart: @@ -142,17 +154,7 @@ mybatis-plus: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl -#eureka配置 -eureka: - client: - service-url: - defaultZone: http://127.0.0.1:9000/eureka/ - register-with-eureka: true - fetch-registry: true - instance: - #配置使用ip地址来注册(默认是主机名称) - prefer-ip-address: true - #心跳检测暂时不配置 +# Nacos注册中心/配置中心 #feign内部服务调用超时配置 feign: @@ -173,24 +175,31 @@ rocketmq: # Seata Config seata: - application-id: goods-service + application-id: ${spring.application.name} tx-service-group: my_test_tx_group service: vgroup-mapping: - # 此处配置对应Server端配置registry.eureka.application的值 my_test_tx_group: default registry: - type: eureka - eureka: - service-url: http://127.0.0.1:9000/eureka/ - weight: 1 + type: nacos + nacos: + application: seata-server + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public + config: + type: nacos + nacos: + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public #springboot admin相关配置 management: endpoints: web: exposure: - include: "*" #'prometheus,health' + include: "health,prometheus,info" exclude: "shutdown" base-path: /actuator endpoint: @@ -215,6 +224,8 @@ management: enabled: false elasticsearch: enabled: false + mail: + enabled: false #日志配置 logging: diff --git a/siam-goods/pom.xml b/siam-goods/pom.xml index a77ca89..6a7e39b 100644 --- a/siam-goods/pom.xml +++ b/siam-goods/pom.xml @@ -32,8 +32,6 @@ UTF-8 - 1.8 - 1.8 \ No newline at end of file diff --git a/siam-mall/mall-api/pom.xml b/siam-mall/mall-api/pom.xml index 52a74e0..c2991dc 100644 --- a/siam-mall/mall-api/pom.xml +++ b/siam-mall/mall-api/pom.xml @@ -16,8 +16,6 @@ UTF-8 - 1.8 - 1.8 @@ -37,7 +35,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 exec diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallGoods.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallGoods.java index 0e9a8e5..247cdd6 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallGoods.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallGoods.java @@ -4,8 +4,7 @@ import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; @@ -14,7 +13,7 @@ @Data @TableName("tb_points_mall_goods") -@ApiModel(value = "商品表") + @Schema(description= "商品表") public class PointsMallGoods { @TableField(exist = false) @@ -33,70 +32,70 @@ public class PointsMallGoods { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "商品名称") + @Schema(description = "商品名称") private String name; - @ApiModelProperty(notes = "商品主图") + @Schema(description = "商品主图") private String mainImage; - @ApiModelProperty(notes = "商品子图") + @Schema(description = "商品子图") private String subImages; - @ApiModelProperty(notes = "商品详情") + @Schema(description = "商品详情") private String detail; - @ApiModelProperty(notes = "详情图片") + @Schema(description = "详情图片") private String detailImages; - @ApiModelProperty(notes = "一口价") + @Schema(description = "一口价") private BigDecimal price; - @ApiModelProperty(notes = "库存") + @Schema(description = "库存") private Integer stock; - @ApiModelProperty(notes = "是否热门") + @Schema(description = "是否热门") private Boolean isHot; - @ApiModelProperty(notes = "是否新品") + @Schema(description = "是否新品") private Boolean isNew; - @ApiModelProperty(notes = "状态 1=上架 2=下架") + @Schema(description = "状态 1=上架 2=下架") private Integer status; - @ApiModelProperty(notes = "是否开启促销 0-否 1-是") + @Schema(description = "是否开启促销 0-否 1-是") private Boolean isSale; - @ApiModelProperty(notes = "折扣价") + @Schema(description = "折扣价") private BigDecimal salePrice; - @ApiModelProperty(notes = "月销量") + @Schema(description = "月销量") private Integer monthlySales; - @ApiModelProperty(notes = "累计销量") + @Schema(description = "累计销量") private Integer totalSales; - @ApiModelProperty(notes = "累计评价") + @Schema(description = "累计评价") private Integer totalComments; - @ApiModelProperty(notes = "优惠名称") + @Schema(description = "优惠名称") private String preferentialName; - @ApiModelProperty(notes = "包装费") + @Schema(description = "包装费") private BigDecimal packingCharges; - @ApiModelProperty(notes = "制作时长(分钟)") + @Schema(description = "制作时长(分钟)") private BigDecimal productTime; - @ApiModelProperty(notes = "兑换商品所需积分数量") + @Schema(description = "兑换商品所需积分数量") private Integer exchangePoints; - @ApiModelProperty(notes = "排序号") + @Schema(description = "排序号") private Integer sortNumber; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; //页码 diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallGoodsSpecification.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallGoodsSpecification.java index f06ac9e..33076be 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallGoodsSpecification.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallGoodsSpecification.java @@ -3,33 +3,32 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.Date; @Data @TableName("tb_points_mall_goods_specification") -@ApiModel(value = "商品规格表") + @Schema(description= "商品规格表") public class PointsMallGoodsSpecification { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "商品id") + @Schema(description = "商品id") private Integer goodsId; - @ApiModelProperty(notes = "商品规格名称") + @Schema(description = "商品规格名称") private String name; - @ApiModelProperty(notes = "排序号") + @Schema(description = "排序号") private Integer sortNumber; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; //页码 diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallGoodsSpecificationOption.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallGoodsSpecificationOption.java index 265c5ab..0dca990 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallGoodsSpecificationOption.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallGoodsSpecificationOption.java @@ -3,8 +3,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; @@ -13,7 +12,7 @@ @Data @TableName("tb_points_mall_goods_specification_option") -@ApiModel(value = "商品规格选项表") + @Schema(description= "商品规格选项表") public class PointsMallGoodsSpecificationOption { private List ids; @@ -21,28 +20,28 @@ public class PointsMallGoodsSpecificationOption { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "商品id") + @Schema(description = "商品id") private Integer goodsId; - @ApiModelProperty(notes = "商品规格id") + @Schema(description = "商品规格id") private Integer goodsSpecificationId; - @ApiModelProperty(notes = "商品商品规格选项名称") + @Schema(description = "商品商品规格选项名称") private String name; - @ApiModelProperty(notes = "单价/加价金额") + @Schema(description = "单价/加价金额") private BigDecimal price; - @ApiModelProperty(notes = "库存 1=有货 2=无货") + @Schema(description = "库存 1=有货 2=无货") private Integer stock; - @ApiModelProperty(notes = "排序号") + @Schema(description = "排序号") private Integer sortNumber; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallMemberGoodsCollect.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallMemberGoodsCollect.java index 2c104a5..c10f248 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallMemberGoodsCollect.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallMemberGoodsCollect.java @@ -2,8 +2,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.Date; @@ -11,7 +10,7 @@ @Data @TableName("tb_points_mall_member_goods_collect") -@ApiModel(value = "用户收藏表") + @Schema(description= "用户收藏表") public class PointsMallMemberGoodsCollect { List goodsIdList; @@ -19,24 +18,24 @@ public class PointsMallMemberGoodsCollect { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "用户id") + @Schema(description = "用户id") private Integer memberId; - @ApiModelProperty(notes = "商品id") + @Schema(description = "商品id") private Integer goodsId; - @ApiModelProperty(notes = "商品是否有效 0=无效 1=有效") + @Schema(description = "商品是否有效 0=无效 1=有效") private Boolean isGoodsExists; - @ApiModelProperty(notes = "商品是否购买 0=未购买 1=已购买") + @Schema(description = "商品是否购买 0=未购买 1=已购买") private Boolean isBuy; - @ApiModelProperty(notes = "收藏类型 1=外卖自提 2=积分商城") + @Schema(description = "收藏类型 1=外卖自提 2=积分商城") private Integer type; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; //页码 diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallMenu.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallMenu.java index 6e5de42..47a535c 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallMenu.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallMenu.java @@ -3,8 +3,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.Date; diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallMenuGoodsRelation.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallMenuGoodsRelation.java index 922b485..0108995 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallMenuGoodsRelation.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallMenuGoodsRelation.java @@ -3,30 +3,29 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.Date; @Data @TableName("tb_points_mall_menu_goods_relation") -@ApiModel(value = "菜单分类商品关系表(多对多)") + @Schema(description= "菜单分类商品关系表(多对多)") public class PointsMallMenuGoodsRelation { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "菜单分类id") + @Schema(description = "菜单分类id") private Integer menuId; - @ApiModelProperty(notes = "商品id") + @Schema(description = "商品id") private Integer goodsId; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; //页码 diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallOrder.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallOrder.java index e75bbdc..6799d0c 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallOrder.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallOrder.java @@ -3,8 +3,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallOrderDetail.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallOrderDetail.java index e036186..638800e 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallOrderDetail.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallOrderDetail.java @@ -3,46 +3,45 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; import java.util.List; @Data -@ApiModel(value = "订单商品详情表") + @Schema(description= "订单商品详情表") @TableName("tb_points_mall_order_detail") public class PointsMallOrderDetail { List ids; - @ApiModelProperty(notes = "主键id") + @Schema(description = "主键id") @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "订单id") + @Schema(description = "订单id") private Long orderId; - @ApiModelProperty(notes = "商品id") + @Schema(description = "商品id") private Integer goodsId; - @ApiModelProperty(notes = "商品名称") + @Schema(description = "商品名称") private String goodsName; - @ApiModelProperty(notes = "商品主图") + @Schema(description = "商品主图") private String mainImage; - @ApiModelProperty(notes = "商品规格 JSON格式") + @Schema(description = "商品规格 JSON格式") private String specList; - @ApiModelProperty(notes = "价格") + @Schema(description = "价格") private BigDecimal price; - @ApiModelProperty(notes = "购买数量") + @Schema(description = "购买数量") private Integer number; - @ApiModelProperty(notes = "小计") + @Schema(description = "小计") private BigDecimal subtotal; private BigDecimal packingCharges; diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallShoppingCart.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallShoppingCart.java index 858181a..cd31726 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallShoppingCart.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/entity/PointsMallShoppingCart.java @@ -3,8 +3,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.Date; @@ -12,7 +11,7 @@ @Data @TableName("tb_points_mall_shopping_cart") -@ApiModel(value = "购物车表") + @Schema(description= "购物车表") public class PointsMallShoppingCart { private List ids; @@ -22,25 +21,25 @@ public class PointsMallShoppingCart { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "用户id") + @Schema(description = "用户id") private Integer memberId; - @ApiModelProperty(notes = "商品id") + @Schema(description = "商品id") private Integer goodsId; - @ApiModelProperty(notes = "商品规格 JSON格式") + @Schema(description = "商品规格 JSON格式") private String specList; - @ApiModelProperty(notes = "购买数量") + @Schema(description = "购买数量") private Integer number; - @ApiModelProperty(notes = "商品是否有效 0=无效 1=有效") + @Schema(description = "商品是否有效 0=无效 1=有效") private Boolean isGoodsExists; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; //页码 diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallGoodsMenuDto.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallGoodsMenuDto.java index ca011f1..b9d7308 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallGoodsMenuDto.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallGoodsMenuDto.java @@ -1,25 +1,25 @@ package com.siam.package_mall.model.dto; import com.siam.package_mall.entity.PointsMallGoods; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Date; public class PointsMallGoodsMenuDto extends PointsMallGoods { - @ApiModelProperty(notes = "菜单id") + @Schema(description = "菜单id") private Integer menuId; - @ApiModelProperty(notes = "菜单名称") + @Schema(description = "菜单名称") private String menuName; - @ApiModelProperty(notes = "指定查询状态为 2=已上架 4=售罄 的商品") + @Schema(description = "指定查询状态为 2=已上架 4=售罄 的商品") private Boolean goodsStatusIn2And4; - @ApiModelProperty(notes = "开始时间") + @Schema(description = "开始时间") private Date startTime; - @ApiModelProperty(notes = "结束时间") + @Schema(description = "结束时间") private Date endTime; public Integer getMenuId() { diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallGoodsSpecificationDto.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallGoodsSpecificationDto.java index a243362..f6f5054 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallGoodsSpecificationDto.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallGoodsSpecificationDto.java @@ -1,27 +1,27 @@ package com.siam.package_mall.model.dto; import com.siam.package_mall.entity.PointsMallGoods; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.math.BigDecimal; public class PointsMallGoodsSpecificationDto extends PointsMallGoods { - @ApiModelProperty(notes = "规格id") + @Schema(description = "规格id") private Integer specificationId; - @ApiModelProperty(notes = "规格名称") + @Schema(description = "规格名称") private String specificationName; - @ApiModelProperty(notes = "商品规格选项id") + @Schema(description = "商品规格选项id") private Integer specificationOptionId; - @ApiModelProperty(notes = "商品规格选项名称") + @Schema(description = "商品规格选项名称") private String specificationOptionName; - @ApiModelProperty(notes = "商品规格选项单价/加价金额") + @Schema(description = "商品规格选项单价/加价金额") private BigDecimal specificationOptionPrice; - @ApiModelProperty(notes = "商品规格选项库存 1代表有货,0代表无货") + @Schema(description = "商品规格选项库存 1代表有货,0代表无货") private Integer specificationOptionStock; public Integer getSpecificationId() { diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallGoodsSpecificationDto11.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallGoodsSpecificationDto11.java index 72e0553..a94da0a 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallGoodsSpecificationDto11.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallGoodsSpecificationDto11.java @@ -1,13 +1,13 @@ package com.siam.package_mall.model.dto; import com.siam.package_mall.entity.PointsMallGoodsSpecification; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; public class PointsMallGoodsSpecificationDto11 extends PointsMallGoodsSpecification { - @ApiModelProperty(notes = "商品名称") + @Schema(description = "商品名称") private String goodsName; - @ApiModelProperty(notes = "商品主图") + @Schema(description = "商品主图") private String goodsMainImage; public String getGoodsName() { diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallGoodsSpecificationOptionDto.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallGoodsSpecificationOptionDto.java index 506ed91..9504fe5 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallGoodsSpecificationOptionDto.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallGoodsSpecificationOptionDto.java @@ -1,18 +1,18 @@ package com.siam.package_mall.model.dto; import com.siam.package_mall.entity.PointsMallGoodsSpecificationOption; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.math.BigDecimal; public class PointsMallGoodsSpecificationOptionDto extends PointsMallGoodsSpecificationOption { - @ApiModelProperty(notes = "规格名称") + @Schema(description = "规格名称") private String specificationName; - @ApiModelProperty(notes = "商品名称") + @Schema(description = "商品名称") private String goodsName; - @ApiModelProperty(notes = "商品主图") + @Schema(description = "商品主图") private String goodsMainImage; public PointsMallGoodsSpecificationOptionDto() { diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallMemberGoodsCollectDto.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallMemberGoodsCollectDto.java index ad2fccd..4ea0b52 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallMemberGoodsCollectDto.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/dto/PointsMallMemberGoodsCollectDto.java @@ -1,13 +1,13 @@ package com.siam.package_mall.model.dto; import com.siam.package_mall.entity.PointsMallMemberGoodsCollect; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @Data public class PointsMallMemberGoodsCollectDto extends PointsMallMemberGoodsCollect { - @ApiModelProperty(notes = "商品名称") + @Schema(description = "商品名称") private String goodsName; } \ No newline at end of file diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/param/PointsMallOrderParam.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/param/PointsMallOrderParam.java index a987607..8cc827a 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/param/PointsMallOrderParam.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/param/PointsMallOrderParam.java @@ -5,26 +5,25 @@ import com.siam.package_mall.entity.PointsMallOrder; import com.siam.package_mall.entity.PointsMallOrderDetail; import com.siam.package_mall.entity.PointsMallOrderRefund; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import org.hibernate.validator.constraints.Range; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; import java.math.BigDecimal; import java.util.Date; import java.util.List; @Data -@ApiModel(value = "订单表") + @Schema(description= "订单表") public class PointsMallOrderParam extends PointsMallOrder { private List ids; - @ApiModelProperty(notes = "下单开始时间") + @Schema(description = "下单开始时间") private Date startCreateTime; - @ApiModelProperty(notes = "下单结束时间") + @Schema(description = "下单结束时间") private Date endCreateTime; Date startTime; @@ -62,7 +61,7 @@ public class PointsMallOrderParam extends PointsMallOrder { BigDecimal actualPrice; @NotNull(message = "主键id不能为空", groups = {ValidGroupOfId.class}) - @ApiModelProperty(notes = "主键id") + @Schema(description = "主键id") private Long id; /** diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/param/SearchParam.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/param/SearchParam.java index e87e10a..0991bb2 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/param/SearchParam.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/param/SearchParam.java @@ -2,7 +2,7 @@ import lombok.Data; -import javax.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotBlank; @Data public class SearchParam { diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/result/PointsMallOrderResult.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/result/PointsMallOrderResult.java index a306c06..1259222 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/result/PointsMallOrderResult.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/result/PointsMallOrderResult.java @@ -2,13 +2,13 @@ import com.siam.package_mall.entity.PointsMallOrder; import com.siam.package_mall.entity.PointsMallOrderDetail; -import io.swagger.annotations.ApiModel; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.List; @Data -@ApiModel(value = "订单表") + @Schema(description= "订单表") public class PointsMallOrderResult extends PointsMallOrder { //订单商品详情列表 diff --git a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/vo/PointsMallOrderVo.java b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/vo/PointsMallOrderVo.java index e7fad79..51bb7c4 100644 --- a/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/vo/PointsMallOrderVo.java +++ b/siam-mall/mall-api/src/main/java/com/siam/package_mall/model/vo/PointsMallOrderVo.java @@ -1,13 +1,13 @@ package com.siam.package_mall.model.vo; import com.siam.package_mall.entity.PointsMallOrderDetail; -import io.swagger.annotations.ApiModel; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.List; @Data -@ApiModel(value = "订单表") + @Schema(description= "订单表") public class PointsMallOrderVo { private Object order; diff --git a/siam-mall/mall-provider/pom.xml b/siam-mall/mall-provider/pom.xml index 4eac0ee..9ef3ea3 100644 --- a/siam-mall/mall-provider/pom.xml +++ b/siam-mall/mall-provider/pom.xml @@ -16,8 +16,6 @@ UTF-8 - 1.8 - 1.8 4.1.1 @@ -78,72 +76,40 @@ - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - 2.1.2.RELEASE - - - - - org.springframework.cloud - spring-cloud-starter-netflix-hystrix - 2.1.2.RELEASE - - - - - org.springframework.cloud - spring-cloud-starter-hystrix-dashboard - 1.2.3.RELEASE - - - + com.alibaba.cloud - spring-cloud-starter-alibaba-seata - 2021.1 - - - io.seata - seata-spring-boot-starter - - + spring-cloud-starter-alibaba-nacos-discovery + - io.seata - seata-spring-boot-starter - 1.3.0 + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config org.springframework.boot spring-boot-starter-actuator - 2.3.3.RELEASE io.micrometer micrometer-registry-prometheus - 1.5.4 - - - - - - - net.logstash.logback logstash-logback-encoder - 6.6 + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui @@ -153,7 +119,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 com.siam.package_mall.MallApplication diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/MallApplication.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/MallApplication.java index b62fb22..d71af94 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/MallApplication.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/MallApplication.java @@ -1,19 +1,19 @@ package com.siam.package_mall; -import org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; -import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; -//@EnableHystrix -//@EnableHystrixDashboard -@EnableCircuitBreaker @EnableFeignClients("com.siam") -@EnableEurekaClient -@SpringBootApplication(scanBasePackages = "com.siam", exclude = {RocketMQAutoConfiguration.class}) +@EnableDiscoveryClient +@SpringBootApplication(scanBasePackages = "com.siam", exclude = { + MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class +}) @MapperScan(basePackages = {"com.siam.**.mapper"}) public class MallApplication { diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/config/MybatisPlusConfig.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/config/MybatisPlusConfig.java index 3d6cb43..a56df58 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/config/MybatisPlusConfig.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/config/MybatisPlusConfig.java @@ -1,6 +1,8 @@ package com.siam.package_mall.config; -import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -19,8 +21,11 @@ public class MybatisPlusConfig { * 分页插件 */ @Bean - public PaginationInterceptor paginationInterceptor() { - return new PaginationInterceptor(); + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); + interceptor.addInnerInterceptor(paginationInnerInterceptor); + return interceptor; } } \ No newline at end of file diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/config/Swagger2Config.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/config/Swagger2Config.java deleted file mode 100644 index 87cc4f7..0000000 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/config/Swagger2Config.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.siam.package_mall.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; - -@Configuration -@EnableSwagger2 -public class Swagger2Config { - - @Bean - public Docket createRestApi() { - return new Docket(DocumentationType.SWAGGER_2) - .apiInfo(apiInfo()) - .select() - .apis(RequestHandlerSelectors.basePackage("com.siam"))//扫描包路径 - .paths(PathSelectors.any()) - .build(); - } - - // 构建api文档的详细信息函数,注意这里的注解引用的是哪个 - private ApiInfo apiInfo() { - return new ApiInfoBuilder() - .title("暹罗外卖-促销服务接口文档")//页面标题 - .description("")//描述 - .version("1.0")//版本号 - .build(); - } -} \ No newline at end of file diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallCouponsController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallCouponsController.java index 9a620a3..c705a32 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallCouponsController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallCouponsController.java @@ -7,8 +7,9 @@ import com.siam.package_common.entity.BasicResult; import com.siam.package_common.constant.BasicResultCode; import com.siam.package_mall.entity.PointsMallCoupons; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -19,13 +20,13 @@ @RestController @RequestMapping(value = "/rest/admin/pointsMall/coupons") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台优惠卷接口", description = "AdminPointsMallCouponsController") +@Tag(name = "后台优惠卷接口", description = "AdminPointsMallCouponsController") public class AdminPointsMallCouponsController { @Autowired private PointsMallCouponsService pointsMallCouponsService; - @ApiOperation(value = "新增优惠卷") + @Operation(summary = "新增优惠卷") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallCoupons coupons) { BasicResult basicResult = new BasicResult(); @@ -39,7 +40,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallCoupons } @AdminPermission - @ApiOperation(value = "修改优惠卷-TODO") + @Operation(summary = "修改优惠卷-TODO") @PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) PointsMallCoupons coupons){ BasicResult basicResult = new BasicResult(); @@ -54,7 +55,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) PointsMallCoupons } @AdminPermission - @ApiOperation(value = "删除优惠卷") + @Operation(summary = "删除优惠卷") @DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) PointsMallCoupons param){ BasicResult basicResult = new BasicResult(); @@ -67,7 +68,7 @@ public BasicResult delete(@RequestBody @Validated(value = {}) PointsMallCoupons return basicResult; } - @ApiOperation(value = "查看优惠卷详情(包含关联商品)") + @Operation(summary = "查看优惠卷详情(包含关联商品)") @PostMapping(value = "/selectById") public BasicResult selectById(@RequestBody @Validated(value = {}) PointsMallCoupons param){ BasicData basicResult = new BasicData(); @@ -81,7 +82,7 @@ public BasicResult selectById(@RequestBody @Validated(value = {}) PointsMallCoup return basicResult; } - @ApiOperation(value = "满优惠卷列表") + @Operation(summary = "满优惠卷列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) PointsMallCoupons coupons) { BasicData basicResult = new BasicData(); @@ -92,7 +93,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) PointsMallCoupons co return BasicResult.success(page); } - @ApiOperation(value = "优惠卷时间修改(延长)") + @Operation(summary = "优惠卷时间修改(延长)") @PostMapping(value = "/updateEndTime") public BasicResult updateEndTime(@RequestBody @Validated(value = {}) PointsMallCoupons coupons){ BasicResult basicResult = new BasicResult(); diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallCouponsGoodsRelationController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallCouponsGoodsRelationController.java index 3bec1fa..9ceb0c0 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallCouponsGoodsRelationController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallCouponsGoodsRelationController.java @@ -7,8 +7,9 @@ import com.siam.package_common.constant.BasicResultCode; import com.siam.package_common.util.GsonUtils; import com.siam.package_mall.entity.PointsMallCouponsGoodsRelation; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -19,13 +20,13 @@ @RestController @RequestMapping(value = "/rest/admin/pointsMall/couponsGoodsRelation") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台优惠卷接口", description = "AdminPointsMallCouponsController") +@Tag(name = "后台优惠卷接口", description = "AdminPointsMallCouponsController") public class AdminPointsMallCouponsGoodsRelationController { @Autowired private PointsMallCouponsGoodsRelationService pointsMallCouponsGoodsRelationService; - @ApiOperation(value = "新增优惠卷商品关系") + @Operation(summary = "新增优惠卷商品关系") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallCouponsGoodsRelation param) { BasicResult basicResult = new BasicResult(); @@ -39,7 +40,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallCouponsG return basicResult; } - @ApiOperation(value = "优惠卷商品关系列表查询") + @Operation(summary = "优惠卷商品关系列表查询") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) PointsMallCouponsGoodsRelation couponsGoodsRelation) { BasicData basicResult = new BasicData(); diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallCouponsMemberRelationController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallCouponsMemberRelationController.java index 5cb2240..09b3197 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallCouponsMemberRelationController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallCouponsMemberRelationController.java @@ -11,8 +11,9 @@ import com.siam.package_mall.entity.PointsMallCouponsMemberRelation; import com.siam.package_user.entity.Member; import com.siam.package_user.feign.MemberFeignApi; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -25,7 +26,7 @@ @RestController @RequestMapping(value = "/rest/admin/pointsMall/couponsMemberRelation") @Transactional(rollbackFor = Exception.class) -@Api(tags = "管理端优惠卷用关系接口", description = "AdminPointsMallCouponsMemberRelationController") +@Tag(name = "管理端优惠卷用关系接口", description = "AdminPointsMallCouponsMemberRelationController") public class AdminPointsMallCouponsMemberRelationController { @Autowired @@ -41,7 +42,7 @@ public class AdminPointsMallCouponsMemberRelationController { private AliyunSms aliyunSms; - @ApiOperation(value = "赠送优惠卷") + @Operation(summary = "赠送优惠卷") @PostMapping(value = "/giveCoupons") public BasicResult giveCoupons(@RequestBody @Validated(value = {}) PointsMallCouponsMemberRelation param) { BasicResult basicResult = new BasicResult(); @@ -96,7 +97,7 @@ public BasicResult giveCoupons(@RequestBody @Validated(value = {}) PointsMallCou return basicResult; } - @ApiOperation(value = "赠送优惠卷(单发)") + @Operation(summary = "赠送优惠卷(单发)") @PostMapping(value = "/giveSingleCoupons") public BasicResult giveSingleCoupons(@RequestBody @Validated(value = {}) PointsMallCouponsMemberRelation param) { BasicResult basicResult = new BasicResult(); diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallFullReductionRuleController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallFullReductionRuleController.java index 10bb0e4..0941310 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallFullReductionRuleController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallFullReductionRuleController.java @@ -8,8 +8,9 @@ import com.siam.package_common.entity.BasicResult; import com.siam.package_common.constant.BasicResultCode; import com.siam.package_mall.entity.PointsMallFullReductionRule; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -18,14 +19,14 @@ @RestController @RequestMapping(value = "/rest/admin/pointsMall/fullReductionRule") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台满减规则模块相关接口", description = "AdminPointsMallFullReductionRuleController") +@Tag(name = "后台满减规则模块相关接口", description = "AdminPointsMallFullReductionRuleController") public class AdminPointsMallFullReductionRuleController { @Autowired private PointsMallFullReductionRuleService pointsMallFullReductionRuleService; - @ApiOperation(value = "新增满减规则") + @Operation(summary = "新增满减规则") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallFullReductionRule fullReductionRule){ BasicResult basicResult = new BasicResult(); @@ -39,7 +40,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallFullRedu } @AdminPermission - @ApiOperation(value = "修改满减规则") + @Operation(summary = "修改满减规则") @PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) PointsMallFullReductionRule fullReductionRule){ BasicResult basicResult = new BasicResult(); @@ -53,7 +54,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) PointsMallFullRedu } @AdminPermission - @ApiOperation(value = "删除满减规则") + @Operation(summary = "删除满减规则") @DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) PointsMallFullReductionRule param){ BasicResult basicResult = new BasicResult(); @@ -66,7 +67,7 @@ public BasicResult delete(@RequestBody @Validated(value = {}) PointsMallFullRedu return basicResult; } - @ApiOperation(value = "查看满减规则详情") + @Operation(summary = "查看满减规则详情") @PostMapping(value = "/selectById") public BasicResult selectById(@RequestBody @Validated(value = {}) PointsMallFullReductionRule param){ BasicData basicResult = new BasicData(); @@ -81,7 +82,7 @@ public BasicResult selectById(@RequestBody @Validated(value = {}) PointsMallFull } - @ApiOperation(value = "满减规则列表") + @Operation(summary = "满减规则列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) PointsMallFullReductionRule fullReductionRule) { BasicData basicResult = new BasicData(); diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallGoodsController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallGoodsController.java index 8f58a5d..7798f6f 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallGoodsController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallGoodsController.java @@ -18,10 +18,16 @@ import com.siam.package_mall.model.dto.PointsMallGoodsMenuDto; import com.siam.package_mall.model.example.PointsMallMenuGoodsRelationExample; import com.siam.package_mall.service.*; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.poi.xssf.usermodel.XSSFWorkbook; @@ -31,7 +37,7 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -43,7 +49,7 @@ @RestController @RequestMapping(value = "/rest/admin/pointsMall/goods") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台商品模块相关接口", description = "AdminPointsMallGoodsController") +@Tag(name = "后台商品模块相关接口", description = "AdminPointsMallGoodsController") public class AdminPointsMallGoodsController { @Autowired private PointsMallGoodsService pointsMallGoodsService; @@ -69,7 +75,7 @@ public class AdminPointsMallGoodsController { @Autowired private PointsMallCouponsGoodsRelationFeignApi pointsMallCouponsGoodsRelationFeignApi; - @ApiOperation(value = "商品列表") + @Operation(summary = "商品列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) PointsMallGoodsMenuDto goodsPointsMallMenuDto){ BasicData basicResult = new BasicData(); @@ -80,7 +86,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) PointsMallGoodsMenuD } - @ApiOperation(value = "新增商品") + @Operation(summary = "新增商品") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallGoods goods){ BasicResult basicResult = new BasicResult(); @@ -144,7 +150,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallGoods go } @AdminPermission - @ApiOperation(value = "修改商品") + @Operation(summary = "修改商品") @PostMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) PointsMallGoods goods){ BasicResult basicResult = new BasicResult(); @@ -189,7 +195,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) PointsMallGoods go } @AdminPermission - @ApiOperation(value = "删除商品") + @Operation(summary = "删除商品") @PostMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) PointsMallGoods param){ BasicResult basicResult = new BasicResult(); @@ -224,7 +230,7 @@ public BasicResult delete(@RequestBody @Validated(value = {}) PointsMallGoods pa return basicResult; } - @ApiOperation(value = "导入商品Excel报表") + @Operation(summary = "导入商品Excel报表") @PostMapping(value = "/import") public BasicResult importPointsMallGoods(@RequestParam(value = "file", required = true) MultipartFile file){ BasicResult basicResult = new BasicResult(); @@ -267,12 +273,7 @@ public BasicResult importPointsMallGoods(@RequestParam(value = "file", required return basicResult; } - @ApiOperation(value = "导出商品Excel报表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) - @GetMapping(value = "/export") + @Operation(summary = "导出商品Excel报表")@GetMapping(value = "/export") public void exportPointsMallGoods(int pageNo, int pageSize, PointsMallGoods goods, HttpServletResponse response){ try { // 生成Excel数据 @@ -302,12 +303,7 @@ public void exportPointsMallGoods(int pageNo, int pageSize, PointsMallGoods good } } - @ApiOperation(value = "菜单状态修改(启用或禁用)") - @ApiImplicitParams({ - @ApiImplicitParam(name = "ids", value = "商品主键id集合(批量删除时id以逗号分隔)", required = true, paramType = "query", dataType = "String"), - @ApiImplicitParam(name = "status", value = "是否启用 0-上架、1-下架", required = true, paramType = "query", dataType = "int") - }) - @DeleteMapping(value = "/update_status") + @Operation(summary = "菜单状态修改(启用或禁用)")@DeleteMapping(value = "/update_status") public BasicResult updateStatus(@RequestBody @Validated(value = {}) PointsMallGoods param){ BasicResult basicResult = new BasicResult(); @@ -319,7 +315,7 @@ public BasicResult updateStatus(@RequestBody @Validated(value = {}) PointsMallGo } - @ApiOperation(value = "获取单个商品详情信息") + @Operation(summary = "获取单个商品详情信息") @PostMapping(value = "/getById") public BasicResult getById(@RequestBody @Validated(value = {}) PointsMallGoods param){ BasicData basicResult = new BasicData(); @@ -344,38 +340,7 @@ public BasicResult getById(@RequestBody @Validated(value = {}) PointsMallGoods p } - /*@ApiOperation(value = "商品规格信息列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "商品名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "categoryId", value = "分类id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "categoryName", value = "分类名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "brandId", value = "品牌id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "brandName", value = "品牌名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "mainImage", value = "商品主图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "subImages", value = "商品子图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specList", value = "商品规格", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "detail", value = "商品详情", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "detailImages", value = "详情图片", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "一口价", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "salePrice", value = "折扣价", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "monthlySales", value = "月销量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "totalSales", value = "累计销量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "totalComments", value = "累计评价", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "stock", value = "库存", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isHot", value = "是否热门", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "isNew", value = "是否新品", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "specificationId", value = "规格id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "specificationName", value = "规格名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specificationOptionId", value = "商品规格选项id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "specificationOptionName", value = "商品规格选项名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specificationOptionPrice", value = "商品规格选项单价/加价金额", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "specificationOptionStock", value = "商品规格选项库存 1代表有货,0代表无货", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) - @PostMapping(value = "/listSpecification") + /*@Operation(summary = "商品规格信息列表")@PostMapping(value = "/listSpecification") public BasicResult listSpecification(int pageNo, int pageSize, PointsMallGoodsSpecificationDto goodsSpecificationDto){ BasicData basicResult = new BasicData(); diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallGoodsSpecificationController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallGoodsSpecificationController.java index a784187..818e3a7 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallGoodsSpecificationController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallGoodsSpecificationController.java @@ -8,8 +8,11 @@ import com.siam.package_common.constant.BasicResultCode; import com.siam.package_mall.entity.PointsMallGoodsSpecification; import com.siam.package_mall.model.example.PointsMallGoodsSpecificationExample; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -21,12 +24,12 @@ @RestController @RequestMapping(value = "/rest/admin/pointsMall/goodsSpecification") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台商品规格模块相关接口", description = "AdminPointsMallGoodsSpecificationController") +@Tag(name = "后台商品规格模块相关接口", description = "AdminPointsMallGoodsSpecificationController") public class AdminPointsMallGoodsSpecificationController { @Autowired private PointsMallGoodsSpecificationService goodsSpecificationService; - @ApiOperation(value = "商品规格列表") + @Operation(summary = "商品规格列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) PointsMallGoodsSpecification goodsSpecification){ BasicData basicResult = new BasicData(); @@ -37,7 +40,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) PointsMallGoodsSpeci } @AdminPermission - @ApiOperation(value = "修改商品规格") + @Operation(summary = "修改商品规格") @PostMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) PointsMallGoodsSpecification goodsSpecification){ BasicResult basicResult = new BasicResult(); @@ -70,13 +73,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) PointsMallGoodsSpe return basicResult; } - /*@ApiOperation(value = "新增商品规格") - @ApiImplicitParams({ - @ApiImplicitParam(name = "name", value = "规格名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序号", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - }) - @PostMapping(value = "/insert") + /*@Operation(summary = "新增商品规格")@PostMapping(value = "/insert") public BasicResult insert(Specification specification){ BasicResult basicResult = new BasicResult(); @@ -88,11 +85,7 @@ public BasicResult insert(Specification specification){ return basicResult; }*/ - /*@ApiOperation(value = "删除商品规格(含批量操作)") - @ApiImplicitParams({ - @ApiImplicitParam(name = "ids", value = "商品规格表主键id(批量删除时id以逗号分隔)", required = true, paramType = "query", dataType = "string"), - }) - @PostMapping(value = "/delete") + /*@Operation(summary = "删除商品规格(含批量操作)")@PostMapping(value = "/delete") public BasicResult delete(@RequestParam(value = "ids", required = true) List ids){ BasicResult basicResult = new BasicResult(); diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallGoodsSpecificationOptionController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallGoodsSpecificationOptionController.java index 26b56ff..c130ca6 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallGoodsSpecificationOptionController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallGoodsSpecificationOptionController.java @@ -11,8 +11,11 @@ import com.siam.package_mall.entity.PointsMallGoodsSpecification; import com.siam.package_mall.entity.PointsMallGoodsSpecificationOption; import com.siam.package_mall.model.example.PointsMallGoodsSpecificationOptionExample; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -25,7 +28,7 @@ @RestController @RequestMapping(value = "/rest/admin/pointsMall/goodsSpecificationOption") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台商品规格选项模块相关接口", description = "AdminPointsMallGoodsSpecificationOptionController") +@Tag(name = "后台商品规格选项模块相关接口", description = "AdminPointsMallGoodsSpecificationOptionController") public class AdminPointsMallGoodsSpecificationOptionController { @Autowired private PointsMallGoodsSpecificationOptionService goodsSpecificationOptionService; @@ -33,7 +36,7 @@ public class AdminPointsMallGoodsSpecificationOptionController { @Autowired private PointsMallGoodsSpecificationService goodsSpecificationService; - @ApiOperation(value = "商品规格选项列表") + @Operation(summary = "商品规格选项列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) PointsMallGoodsSpecificationOptionDto goodsSpecificationOptionDto){ BasicData basicResult = new BasicData(); @@ -43,7 +46,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) PointsMallGoodsSpeci return BasicResult.success(page); } - @ApiOperation(value = "添加商品规格选项") + @Operation(summary = "添加商品规格选项") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallGoodsSpecificationOptionDto goodsSpecificationOptionDto){ BasicData basicResult = new BasicData(); @@ -97,7 +100,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallGoodsSpe } @AdminPermission - @ApiOperation(value = "修改商品规格选项") + @Operation(summary = "修改商品规格选项") @PostMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) PointsMallGoodsSpecificationOptionDto goodsSpecificationOptionDto){ BasicResult basicResult = new BasicResult(); @@ -162,7 +165,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) PointsMallGoodsSpe } @AdminPermission - @ApiOperation(value = "删除商品规格选项(含批量操作)") + @Operation(summary = "删除商品规格选项(含批量操作)") @PostMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) PointsMallGoodsSpecificationOption param){ BasicResult basicResult = new BasicResult(); @@ -194,11 +197,7 @@ public BasicResult delete(@RequestBody @Validated(value = {}) PointsMallGoodsSpe return basicResult; } - /*@ApiOperation(value = "生成商品公共口味") - @ApiImplicitParams({ - @ApiImplicitParam(name = "goodsId", value = "商品id", required = true, paramType = "query", dataType = "int") - }) - @PostMapping(value = "/insertPublicSpecification") + /*@Operation(summary = "生成商品公共口味")@PostMapping(value = "/insertPublicSpecification") public BasicResult insertPublicSpecification(int goodsId){ BasicResult basicResult = new BasicResult(); diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallMenuController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallMenuController.java index 6d003d6..2d6ddf3 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallMenuController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallMenuController.java @@ -9,8 +9,9 @@ import com.siam.package_common.constant.BasicResultCode; import com.siam.package_mall.entity.PointsMallMenu; import com.siam.package_mall.model.example.PointsMallMenuGoodsRelationExample; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -23,7 +24,7 @@ @RestController @RequestMapping(value = "/rest/admin/pointsMall/menu") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台菜单分类模块相关接口", description = "AdminPointsMallMenuController") +@Tag(name = "后台菜单分类模块相关接口", description = "AdminPointsMallMenuController") public class AdminPointsMallMenuController { @Autowired @@ -32,7 +33,7 @@ public class AdminPointsMallMenuController { @Autowired private PointsMallMenuGoodsRelationService menuPointsMallGoodsRelationService; - @ApiOperation(value = "菜单列表") + @Operation(summary = "菜单列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) PointsMallMenu menu){ BasicData basicResult = new BasicData(); @@ -41,7 +42,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) PointsMallMenu menu) return BasicResult.success(page); } - @ApiOperation(value = "菜单创建") + @Operation(summary = "菜单创建") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallMenu menu){ BasicResult basicResult = new BasicResult(); @@ -57,7 +58,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallMenu men } @AdminPermission - @ApiOperation(value = "菜单修改") + @Operation(summary = "菜单修改") @PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) PointsMallMenu menu){ BasicResult basicResult = new BasicResult(); @@ -72,7 +73,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) PointsMallMenu men } @AdminPermission - @ApiOperation(value = "菜单删除") + @Operation(summary = "菜单删除") @DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) PointsMallMenu param){ BasicResult basicResult = new BasicResult(); @@ -96,7 +97,7 @@ public BasicResult delete(@RequestBody @Validated(value = {}) PointsMallMenu par return basicResult; } - @ApiOperation(value = "获取单个菜单分类详情信息") + @Operation(summary = "获取单个菜单分类详情信息") @PostMapping(value = "/getById") public BasicResult getById(@RequestBody @Validated(value = {}) PointsMallMenu param){ BasicData basicResult = new BasicData(); diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallOrderController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallOrderController.java index c58ed55..2f8ed93 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallOrderController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallOrderController.java @@ -9,10 +9,8 @@ import com.siam.package_mall.model.result.PointsMallOrderResult; import com.siam.package_mall.service.PointsMallOrderService; import com.siam.package_mall.entity.PointsMallOrder; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; @@ -20,37 +18,35 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import java.text.ParseException; import java.util.*; @RestController @RequestMapping(value = "/rest/admin/pointsMall/order") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台订单模块相关接口", description = "AdminPointsMallOrderController") +@Tag(name = "后台订单模块相关接口", description = "AdminPointsMallOrderController") public class AdminPointsMallOrderController { @Resource(name = "pointsMallOrderServiceImpl") private PointsMallOrderService orderService; - @ApiOperation(value = "订单列表") + @Operation(summary = "订单列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) PointsMallOrderParam param){ Page page = orderService.getListByPageWithAsc(param); return BasicResult.success(page); } - @ApiOperation(value = "订单列表(附带订单商品详情)") + @Operation(summary = "订单列表(附带订单商品详情)") @PostMapping(value = "/listWithDetail") public BasicResult listWithDetail(@RequestBody @Validated(value = {}) PointsMallOrderParam param){ Page page = orderService.getListByPageWithAsc(param); return BasicResult.success(page); } - @ApiOperation("打印小票") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id" ,value="订单商品详情表主键id",required = true,paramType = "query",dataType="int") - }) + @Operation(summary = "打印小票") + @PostMapping(value = "/printRceceipts") public BasicResult printRceceipts(@RequestBody @Validated(value = {}) PointsMallOrderParam param){ for(String id : param.getIds()){ orderService.printRceceipts(Long.valueOf(id)); @@ -58,7 +54,7 @@ public BasicResult printRceceipts(@RequestBody @Validated(value = {}) PointsMall return BasicResult.success(); } - @ApiOperation(value = "查询单个订单信息") + @Operation(summary = "查询单个订单信息") @PostMapping(value = "/selectById") public BasicResult selectById(@RequestBody @Validated(value = {}) PointsMallOrderParam param){ PointsMallOrder dbPointsMallOrder = orderService.selectByPrimaryKey(param.getId()); @@ -68,114 +64,82 @@ public BasicResult selectById(@RequestBody @Validated(value = {}) PointsMallOrde return BasicResult.success(dbPointsMallOrder); } - @ApiOperation(value = "批量修改订单的是否已打印状态为已打印") + @Operation(summary = "批量修改订单的是否已打印状态为已打印") @PostMapping(value = "/batchUpdateIsPrintedTrue") public BasicResult batchUpdateIsPrintedTrue(@RequestBody @Validated(value = {}) PointsMallOrderParam param){ orderService.batchUpdateIsPrintedTrue(param); return BasicResult.success(); } - @ApiOperation(value = "今日订单列表") + @Operation(summary = "今日订单列表") @PostMapping(value = "/todayPointsMallOrderList") public BasicResult todayPointsMallOrderList(@RequestBody @Validated(value = {}) PointsMallOrderParam param){ Page page = orderService.getListByTodayOrderWithAsc(param); return BasicResult.success(page); } - @ApiOperation(value = "查询所有订单标签页的待处理数量") + @Operation(summary = "查询所有订单标签页的待处理数量") @PostMapping(value = "/selectAllTabWaitHandleNum") public BasicResult selectAllTabWaitHandleNum(@RequestBody @Validated(value = {}) PointsMallOrderParam param){ Map map = orderService.selectAllTabWaitHandleNum(param); return BasicResult.success(map); } - @ApiOperation(value = "查询所有已付款未打印的订单") + @Operation(summary = "查询所有已付款未打印的订单") @PostMapping(value = "/waitPrintPointsMallOrderList") public BasicResult waitPrintPointsMallOrderList(@RequestBody @Validated(value = {}) PointsMallOrderParam param){ List pointsMallOrders = orderService.waitPrintPointsMallOrderList(param); return BasicResult.success(pointsMallOrders); } - @ApiOperation(value = "订单统计(支付成功订单数量、取消订单数量、退款订单数量,按自取或者外卖分开)") - @ApiImplicitParams({ - @ApiImplicitParam(name = "startCreateTime", value = "下单开始时间", required = false, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "endCreateTime", value = "下单结束时间", required = false, paramType = "query", dataType = "Date"), - }) + @Operation(summary = "订单统计(支付成功订单数量、取消订单数量、退款订单数量,按自取或者外卖分开)") @PostMapping(value = "/countPointsMallOrder") public BasicResult countPointsMallOrder(@RequestBody @Validated(value = {}) PointsMallOrderParam param){ Map count = orderService.countOrder(param); return BasicResult.success(count); } - @ApiOperation(value = "售后处理订单列表") + @Operation(summary = "售后处理订单列表") @PostMapping(value = "/afterSalesList") public BasicResult afterSalesList(@RequestBody @Validated(value = {}) PointsMallOrderParam param){ Page> page = orderService.getAfterSalesListByPageWithAsc(param); return BasicResult.success(page); } - @ApiOperation(value = "售后处理订单列表") + @Operation(summary = "售后处理订单列表") @PostMapping(value = "/afterSalesListWithDetail") public BasicResult afterSalesListWithDetail(@RequestBody @Validated(value = {}) PointsMallOrderParam param){ Page> page = orderService.getAfterSalesListByPageWithAsc(param); return BasicResult.success(page); } - /** - * 售后处理订单-处理 - * - * @return - * @author 暹罗 - */ @PostMapping(value = "/auditAfterSalesOrder") public BasicResult auditAfterSalesOrder(@RequestBody @Validated(value = {ValidGroupOfId.class, ValidGroupOfAudit.class}) PointsMallOrderParam orderParam){ orderService.auditAfterSalesOrder(orderParam); return BasicResult.success(); } - /** - * 查询订单统计数据 - * PS;一次性将所有数据全部查出来,而不是每次选择时间段时来实时请求数据 - */ @PostMapping(value = "/statistic") public BasicResult statisticPointsMallOrder(@RequestBody @Validated(value = {}) PointsMallOrderParam param) throws ParseException { Map map = orderService.statistic(param); return BasicResult.success(map); } - /** - * 订单发货 - * - * @return - * @author 暹罗 - */ @PostMapping(value = "/deliver") public BasicResult deliver(@RequestBody @Validated(value = {}) PointsMallOrderParam param){ orderService.deliver(param); return BasicResult.success(); } - /** - * 修改快递单号 - * - * @return - * @author 暹罗 - */ @PostMapping(value = "/updateLogisticsNo") public BasicResult updateLogisticsNo(@RequestBody @Validated(value = {}) PointsMallOrderParam param){ orderService.updateLogisticsNo(param); return BasicResult.success(); } - /** - * 修改订单信息 - * - * @return - * @author 暹罗 - */ @PostMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) PointsMallOrderParam param){ orderService.updateByAdmin(param); return BasicResult.success(); } -} \ No newline at end of file +} diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallOrderDetailController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallOrderDetailController.java index bc733a2..8946355 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallOrderDetailController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallOrderDetailController.java @@ -6,10 +6,16 @@ import com.siam.package_common.entity.BasicResult; import com.siam.package_common.constant.BasicResultCode; import com.siam.package_mall.entity.PointsMallOrderDetail; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -18,28 +24,12 @@ @RestController @RequestMapping(value = "/rest/admin/pointsMall/orderDetail") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台订单商品详情模块相关接口", description = "AdminPointsMallOrderDetailController") +@Tag(name = "后台订单商品详情模块相关接口", description = "AdminPointsMallOrderDetailController") public class AdminPointsMallOrderDetailController { @Autowired private PointsMallOrderDetailService orderDetailService; - @ApiOperation(value = "订单商品详情列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "订单商品详情表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "orderId", value = "订单id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "goodsId", value = "商品id", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsName", value = "商品名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specList", value = "商品规格 JSON格式", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsSpecs", value = "规格组合 JSON格式", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "价格", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "number", value = "购买数量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "subtotal", value = "小计", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "remark", value = "备注", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) - @PostMapping(value = "/list") + @Operation(summary = "订单商品详情列表")@PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) PointsMallOrderDetail orderDetail){ BasicData basicResult = new BasicData(); @@ -49,20 +39,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) PointsMallOrderDetai } - @ApiOperation(value = "新增订单商品详情") - @ApiImplicitParams({ - @ApiImplicitParam(name = "orderId", value = "订单id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "goodsId", value = "商品id", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsName", value = "商品名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specList", value = "商品规格 JSON格式", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsSpecs", value = "规格组合 JSON格式", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "价格", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "number", value = "购买数量", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "subtotal", value = "小计", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "remark", value = "备注", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - }) - @PostMapping(value = "/insert") + @Operation(summary = "新增订单商品详情")@PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallOrderDetail orderDetail){ BasicResult basicResult = new BasicResult(); @@ -74,21 +51,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallOrderDet return basicResult; } - @ApiOperation(value = "修改订单商品详情") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "订单商品详情表主键id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "orderId", value = "订单id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "goodsId", value = "商品id", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsName", value = "商品名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specList", value = "商品规格 JSON格式", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsSpecs", value = "规格组合 JSON格式", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "价格", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "number", value = "购买数量", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "subtotal", value = "小计", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "remark", value = "备注", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - }) - @PostMapping(value = "/update") + @Operation(summary = "修改订单商品详情")@PostMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) PointsMallOrderDetail orderDetail){ BasicResult basicResult = new BasicResult(); @@ -100,11 +63,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) PointsMallOrderDet return basicResult; } - @ApiOperation(value = "删除订单商品详情(含批量操作)") - @ApiImplicitParams({ - @ApiImplicitParam(name = "ids", value = "订单商品详情表主键id(批量删除时id以逗号分隔)", required = true, paramType = "query", dataType = "string"), - }) - @PostMapping(value = "/delete") + @Operation(summary = "删除订单商品详情(含批量操作)")@PostMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) PointsMallOrderDetail param){ BasicResult basicResult = new BasicResult(); diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallOrderLogisticsController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallOrderLogisticsController.java index 9a72daf..364a915 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallOrderLogisticsController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallOrderLogisticsController.java @@ -5,8 +5,9 @@ import com.siam.package_common.entity.BasicData; import com.siam.package_common.entity.BasicResult; import com.siam.package_mall.entity.PointsMallOrderLogistics; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -18,13 +19,13 @@ @RestController @RequestMapping(value = "/rest/admin/pointsMall/orderLogistics") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台订单物流跟踪信息模块相关接口", description = "AdminPointsMallOrderLogisticsController") +@Tag(name = "后台订单物流跟踪信息模块相关接口", description = "AdminPointsMallOrderLogisticsController") public class AdminPointsMallOrderLogisticsController { @Autowired private PointsMallOrderLogisticsService orderLogisticsService; - @ApiOperation(value = "订单物流跟踪信息列表") + @Operation(summary = "订单物流跟踪信息列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) PointsMallOrderLogistics orderLogistics){ BasicData basicResult = new BasicData(); diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallShoppingCartController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallShoppingCartController.java index adf4139..04efac8 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallShoppingCartController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/admin/AdminPointsMallShoppingCartController.java @@ -6,8 +6,9 @@ import com.siam.package_common.entity.BasicResult; import com.siam.package_common.constant.BasicResultCode; import com.siam.package_mall.entity.PointsMallShoppingCart; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -16,12 +17,12 @@ @RestController @RequestMapping(value = "/rest/admin/pointsMall/shoppingCart") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台购物车模块相关接口", description = "AdminPointsMallShoppingCartController") +@Tag(name = "后台购物车模块相关接口", description = "AdminPointsMallShoppingCartController") public class AdminPointsMallShoppingCartController { @Autowired private PointsMallShoppingCartService shoppingCartService; - @ApiOperation(value = "购物车列表") + @Operation(summary = "购物车列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) PointsMallShoppingCart shoppingCart){ BasicData basicResult = new BasicData(); @@ -32,7 +33,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) PointsMallShoppingCa } - @ApiOperation(value = "新增购物车") + @Operation(summary = "新增购物车") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallShoppingCart shoppingCart){ BasicResult basicResult = new BasicResult(); @@ -45,7 +46,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallShopping return basicResult; } - @ApiOperation(value = "修改购物车") + @Operation(summary = "修改购物车") @PostMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) PointsMallShoppingCart shoppingCart){ BasicResult basicResult = new BasicResult(); @@ -58,7 +59,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) PointsMallShopping return basicResult; } - @ApiOperation(value = "删除购物车(含批量操作)") + @Operation(summary = "删除购物车(含批量操作)") @PostMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) PointsMallShoppingCart param){ BasicResult basicResult = new BasicResult(); diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallCouponsMemberRelationController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallCouponsMemberRelationController.java index 29f3f43..2076e8c 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallCouponsMemberRelationController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallCouponsMemberRelationController.java @@ -9,22 +9,28 @@ import com.siam.package_common.constant.BasicResultCode; import com.siam.package_mall.entity.PointsMallCouponsMemberRelation; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.Map; @RestController @RequestMapping(value = "/rest/member/pointsMall/couponsMemberRelation") @Transactional(rollbackFor = Exception.class) -@Api(tags = "优惠卷用关系接口", description = "PointsMallCouponsMemberRelationController") +@Tag(name = "优惠卷用关系接口", description = "PointsMallCouponsMemberRelationController") public class PointsMallCouponsMemberRelationController { @Autowired @@ -36,18 +42,7 @@ public class PointsMallCouponsMemberRelationController { @Autowired private MemberSessionManager memberSessionManager; - @ApiOperation(value = "新增优惠卷用户关系") - @ApiImplicitParams({ - @ApiImplicitParam(name = "couponsId", value = "优惠卷id", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "couponsName", value = "优惠卷名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "memberId", value = "用户id", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "startTime", value = "生效时间", required = false, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "endTime", value = "过期时间", required = false, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "isUsed", value = "是否已经使用,0=未使用,1=已使用", required = false, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "isExpired", value = "是否过期,0=未过期,1=已过期", required = false, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "isValid", value = "是否生效,0-未生效,1-生效中", required = false, paramType = "query", dataType = "Boolean"), - }) - @PostMapping(value = "/insert") + @Operation(summary = "新增优惠卷用户关系")@PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallCouponsMemberRelation couponsMemberRelation) { BasicResult basicResult = new BasicResult(); @@ -59,11 +54,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) PointsMallCouponsM return basicResult; } - @ApiOperation(value = "查看优惠卷关系详情(包含关联优惠卷)") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "主键id", required = true, paramType = "query", dataType = "Integer"), - }) - @PostMapping(value = "/selectById") + @Operation(summary = "查看优惠卷关系详情(包含关联优惠卷)")@PostMapping(value = "/selectById") public BasicResult selectById(@RequestBody @Validated(value = {}) PointsMallCouponsMemberRelation param){ BasicData basicResult = new BasicData(); @@ -77,21 +68,7 @@ public BasicResult selectById(@RequestBody @Validated(value = {}) PointsMallCoup } - @ApiOperation(value = "优惠卷用户关系列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "主键id", required = false, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "couponsId", value = "优惠卷id", required = false, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "couponsName", value = "优惠卷名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "memberId", value = "用户id", required = false, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "startTime", value = "生效时间", required = false, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "endTime", value = "过期时间", required = false, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "isUsed", value = "是否已经使用,0=未使用,1=已使用", required = false, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "isExpired", value = "是否过期,0=未过期,1=已过期", required = false, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "isValid", value = "是否生效,0-未生效,1-生效中", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - }) - @PostMapping(value = "/list") + @Operation(summary = "优惠卷用户关系列表")@PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) PointsMallCouponsMemberRelation couponsMemberRelation, HttpServletRequest request) { BasicData basicResult = new BasicData(); Member loginMember = memberSessionManager.getSession(TokenUtil.getToken()); @@ -103,7 +80,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) PointsMallCouponsMem return BasicResult.success(page); } - @ApiOperation(value = "查询优惠卷数量") + @Operation(summary = "查询优惠卷数量") @PostMapping(value = "/selectCounts") public BasicResult selectCounts(@RequestBody @Validated(value = {}) PointsMallCouponsMemberRelation param){ BasicData basicResult = new BasicData(); diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallFullReductionRuleController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallFullReductionRuleController.java index 949a5cc..f0d15d3 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallFullReductionRuleController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallFullReductionRuleController.java @@ -5,10 +5,16 @@ import com.siam.package_common.entity.BasicData; import com.siam.package_common.entity.BasicResult; import com.siam.package_mall.entity.PointsMallFullReductionRule; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -20,23 +26,13 @@ @RestController @RequestMapping(value = "/rest/pointsMall/fullReductionRule") @Transactional(rollbackFor = Exception.class) -@Api(tags = "满减规则模块相关接口", description = "PointsMallFullReductionRuleController") +@Tag(name = "满减规则模块相关接口", description = "PointsMallFullReductionRuleController") public class PointsMallFullReductionRuleController { @Autowired private PointsMallFullReductionRuleService fullReductionRuleService; - @ApiOperation(value = "满减规则列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "主键id", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "name", value = "满减规则名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "status", value = "状态", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "limitedPrice", value = "分类名称", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "reducedPrice", value = "品牌id", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - }) - @PostMapping(value = "/list") + @Operation(summary = "满减规则列表")@PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) PointsMallFullReductionRule fullReductionRule){ BasicData basicResult = new BasicData(); @@ -45,11 +41,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) PointsMallFullReduct return BasicResult.success(page); } - /*@ApiOperation(value = "查看满减规则详情") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "主键id", required = true, paramType = "query", dataType = "Integer"), - }) - @PostMapping(value = "/selectById") + /*@Operation(summary = "查看满减规则详情")@PostMapping(value = "/selectById") public BasicResult selectById(@RequestParam(value = "id", required = true) int id){ BasicData basicResult = new BasicData(); diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallGoodsController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallGoodsController.java index 8527590..4b3c973 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallGoodsController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallGoodsController.java @@ -14,8 +14,11 @@ import com.siam.package_mall.service.PointsMallGoodsService; import com.siam.package_user.model.param.AdminParam; import com.siam.package_util.feign.SettingFeignApi; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; @@ -32,7 +35,7 @@ @RestController @RequestMapping(value = "/rest/pointsMall/goods") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商品模块相关接口", description = "PointsMallGoodsController") +@Tag(name = "商品模块相关接口", description = "PointsMallGoodsController") public class PointsMallGoodsController { @Autowired private PointsMallGoodsService goodsService; @@ -46,34 +49,7 @@ public class PointsMallGoodsController { @Autowired private SettingFeignApi settingFeignApi; - /*@ApiOperation(value = "商品列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "商品名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "categoryId", value = "分类id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "categoryName", value = "分类名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "brandId", value = "品牌id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "brandName", value = "品牌名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "mainImage", value = "商品主图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "subImages", value = "商品子图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specList", value = "商品规格", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "detail", value = "商品详情", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "detailImages", value = "详情图片", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "一口价", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "salePrice", value = "折扣价", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "monthlySales", value = "月销量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "totalSales", value = "累计销量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "totalComments", value = "累计评价", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "stock", value = "库存", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "productTime", value = "制作时长(分钟)", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "exchangePoints", value = "兑换商品所需积分数量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isHot", value = "是否热门", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "isNew", value = "是否新品", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "status", value = "状态 1=下架 0=上架", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) - @PostMapping(value = "/list") + /*@Operation(summary = "商品列表")@PostMapping(value = "/list") public BasicResult list(int pageNo, int pageSize, PointsMallGoods goods){ BasicData basicResult = new BasicData(); @@ -151,11 +127,7 @@ public BasicResult listByPointsMallMenuId(@RequestBody @Validated(value = {}) Po } - /*@ApiOperation(value = "查询商品的规格组合信息") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品表主键id", required = true, paramType = "query", dataType = "int"), - }) - @PostMapping(value = "/selectSpecificationById") + /*@Operation(summary = "查询商品的规格组合信息")@PostMapping(value = "/selectSpecificationById") public BasicResult selectSpecificationById(PointsMallGoodsSpecificationDto goodsSpecificationDto){ BasicData basicResult = new BasicData(); @@ -181,7 +153,7 @@ public BasicResult selectSpecificationById(PointsMallGoodsSpecificationDto goods return basicResult; }*/ - /*@ApiOperation(value = "本月上新商品列表") + /*@Operation(summary = "本月上新商品列表") @PostMapping(value = "/weekNewGoodsList") public BasicResult weekNewPointsMallGoodsList(){ BasicData basicResult = new BasicData(); @@ -196,7 +168,7 @@ public BasicResult weekNewPointsMallGoodsList(){ return basicResult; }*/ - /*@ApiOperation(value = "好友推荐商品列表") + /*@Operation(summary = "好友推荐商品列表") @PostMapping(value = "/recommendGoodsList") public BasicResult recommendPointsMallGoodsList(){ BasicData basicResult = new BasicData(); @@ -227,7 +199,7 @@ public BasicResult recommendPointsMallGoodsList(){ return basicResult; }*/ - @ApiOperation(value = "猜你喜欢商品列表") + @Operation(summary = "猜你喜欢商品列表") @PostMapping(value = "/guessLikeGoodsList") public BasicResult guessLikePointsMallGoodsList(@RequestBody @Validated(value = {}) AdminParam param){ BasicData basicResult = new BasicData(); @@ -259,7 +231,7 @@ public BasicResult guessLikePointsMallGoodsList(@RequestBody @Validated(value = return basicResult; } - /*@ApiOperation(value = "首页商品推荐列表") + /*@Operation(summary = "首页商品推荐列表") @PostMapping(value = "/homePage/recommendGoodsList") public BasicResult recommendPointsMallGoodsListOfHomePage(){ BasicData basicResult = new BasicData(); @@ -292,7 +264,7 @@ public BasicResult recommendPointsMallGoodsListOfHomePage(){ return basicResult; }*/ - @ApiOperation(value = "推荐展示的商品列表") + @Operation(summary = "推荐展示的商品列表") @PostMapping(value = "/recommendGoodsList") public BasicResult recommendGoodsList(@RequestBody @Validated(value = {}) PointsMallGoods goods){ BasicData basicResult = new BasicData(); diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallGoodsSpecificationController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallGoodsSpecificationController.java index 4c09888..9cf4544 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallGoodsSpecificationController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallGoodsSpecificationController.java @@ -1,7 +1,8 @@ package com.siam.package_mall.controller.member; import com.siam.package_mall.service.PointsMallGoodsSpecificationService; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RequestMapping; @@ -10,7 +11,7 @@ @RestController @RequestMapping(value = "/rest/pointsMall/goodsSpecification") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商品规格模块相关接口", description = "PointsMallGoodsSpecificationController") +@Tag(name = "商品规格模块相关接口", description = "PointsMallGoodsSpecificationController") public class PointsMallGoodsSpecificationController { @Autowired private PointsMallGoodsSpecificationService goodsSpecificationService; diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallGoodsSpecificationOptionController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallGoodsSpecificationOptionController.java index 3ce03a9..c181f97 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallGoodsSpecificationOptionController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallGoodsSpecificationOptionController.java @@ -6,10 +6,16 @@ import com.siam.package_common.entity.BasicResult; import com.siam.package_common.constant.BasicResultCode; import com.siam.package_mall.model.dto.PointsMallGoodsSpecificationOptionDto; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -26,16 +32,12 @@ @RestController @RequestMapping(value = "/rest/pointsMall/goodsSpecificationOption") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商品规格选项模块相关接口", description = "PointsMallGoodsSpecificationOptionController") +@Tag(name = "商品规格选项模块相关接口", description = "PointsMallGoodsSpecificationOptionController") public class PointsMallGoodsSpecificationOptionController { @Autowired private PointsMallGoodsSpecificationOptionService goodsSpecificationOptionService; - @ApiOperation(value = "查询商品规格选项信息") - @ApiImplicitParams({ - @ApiImplicitParam(name = "goodsId", value = "商品id", required = true, paramType = "query", dataType = "int"), - }) - @PostMapping(value = "/selectByGoodsId") + @Operation(summary = "查询商品规格选项信息")@PostMapping(value = "/selectByGoodsId") public BasicResult list(@RequestBody @Validated(value = {}) PointsMallGoodsSpecificationOptionDto goodsSpecificationOptionDto){ BasicData basicResult = new BasicData(); diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallMemberGoodsCollectController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallMemberGoodsCollectController.java index 9814a92..bcc28aa 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallMemberGoodsCollectController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallMemberGoodsCollectController.java @@ -13,14 +13,15 @@ import com.siam.package_mall.entity.PointsMallMemberGoodsCollect; import com.siam.package_mall.model.example.PointsMallMemberGoodsCollectExample; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.List; import java.util.Map; @@ -28,7 +29,7 @@ @RestController @RequestMapping(value = "/rest/member/pointsMall/goodsCollect") @Transactional(rollbackFor = Exception.class) -@Api(tags = "用户商品收藏相关接口", description = "PointsMallMemberGoodsCollectController") +@Tag(name = "用户商品收藏相关接口", description = "PointsMallMemberGoodsCollectController") public class PointsMallMemberGoodsCollectController { @Autowired diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallMenuController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallMenuController.java index 1402a76..25affa0 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallMenuController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallMenuController.java @@ -7,7 +7,8 @@ import com.siam.package_common.constant.BasicResultCode; import com.siam.package_common.constant.Quantity; import com.siam.package_mall.entity.PointsMallMenu; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -24,7 +25,7 @@ @RestController @RequestMapping(value = "/rest/pointsMall/menu") @Transactional(rollbackFor = Exception.class) -@Api(tags = "菜单分类模块相关接口", description = "PointsMallMenuController") +@Tag(name = "菜单分类模块相关接口", description = "PointsMallMenuController") public class PointsMallMenuController { @Autowired diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallOrderController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallOrderController.java index cbf3ed4..d45a451 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallOrderController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallOrderController.java @@ -6,8 +6,9 @@ import com.siam.package_mall.model.vo.PointsMallOrderVo; import com.siam.package_mall.entity.PointsMallOrder; import com.siam.package_mall.service.PointsMallOrderService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.client.exception.MQBrokerException; import org.apache.rocketmq.client.exception.MQClientException; @@ -16,14 +17,14 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import java.util.*; @Slf4j @RestController @RequestMapping(value = "/rest/member/pointsMall/order") @Transactional(rollbackFor = Exception.class) -@Api(tags = "订单模块相关接口", description = "PointsMallOrderController") +@Tag(name = "订单模块相关接口", description = "PointsMallOrderController") public class PointsMallOrderController { @Resource(name = "pointsMallOrderServiceImpl") @@ -125,14 +126,14 @@ public BasicResult returnGoodsWithRefund(@RequestBody @Validated(value = {}) Poi return BasicResult.success(); } - @ApiOperation(value = "修改订单状态为已确认收货") + @Operation(summary = "修改订单状态为已确认收货") @PostMapping(value = "/confirmReceipt") public BasicResult confirmReceipt(@RequestBody @Validated(value = {}) PointsMallOrderParam param){ orderService.confirmReceipt(param); return BasicResult.success(); } - @ApiOperation(value = "删除订单") + @Operation(summary = "删除订单") @PostMapping(value = "/delete") public BasicResult deletePointsMallOrder(@RequestBody @Validated(value = {}) PointsMallOrderParam param){ orderService.delete(param); diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallOrderDetailController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallOrderDetailController.java index ccc309b..abe40f5 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallOrderDetailController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallOrderDetailController.java @@ -1,7 +1,11 @@ package com.siam.package_mall.controller.member; import com.siam.package_mall.service.PointsMallOrderDetailService; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RequestMapping; @@ -10,28 +14,12 @@ @RestController @RequestMapping(value = "/rest/pointsMall/orderDetail") @Transactional(rollbackFor = Exception.class) -@Api(tags = "订单商品详情模块相关接口", description = "PointsMallOrderDetailController") +@Tag(name = "订单商品详情模块相关接口", description = "PointsMallOrderDetailController") public class PointsMallOrderDetailController { @Autowired private PointsMallOrderDetailService orderDetailService; - /*@ApiOperation(value = "订单商品详情列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "订单商品详情表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "orderId", value = "订单id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "goodsId", value = "商品id", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsName", value = "商品名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specList", value = "商品规格 JSON格式", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsSpecs", value = "规格组合 JSON格式", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "价格", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "number", value = "购买数量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "subtotal", value = "小计", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "remark", value = "备注", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) - @PostMapping(value = "/list") + /*@Operation(summary = "订单商品详情列表")@PostMapping(value = "/list") public BasicResult list(int pageNo, int pageSize, PointsMallOrderDetail orderDetail){ BasicData basicResult = new BasicData(); diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallOrderLogisticsController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallOrderLogisticsController.java index 7cc308b..ecdb97e 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallOrderLogisticsController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallOrderLogisticsController.java @@ -11,7 +11,8 @@ import com.siam.package_mall.entity.PointsMallOrder; import com.siam.package_mall.entity.PointsMallOrderLogistics; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -21,15 +22,15 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; import java.util.Map; @Slf4j @RestController @RequestMapping(value = "/rest/member/pointsMall/orderLogistics") @Transactional(rollbackFor = Exception.class) -@Api(tags = "订单物流跟踪信息模块相关接口", description = "PointsMallOrderLogisticsController") +@Tag(name = "订单物流跟踪信息模块相关接口", description = "PointsMallOrderLogisticsController") public class PointsMallOrderLogisticsController { @Resource(name = "pointsMallOrderServiceImpl") diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallPlatformPayController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallPlatformPayController.java index 879ee0c..246ada4 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallPlatformPayController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallPlatformPayController.java @@ -19,8 +19,9 @@ import com.siam.package_user.feign.MemberTradeRecordFeignApi; import com.siam.package_user.model.example.MemberTradeRecordExample; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -30,15 +31,15 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; import java.util.Date; @Slf4j @RestController @RequestMapping(value = "/rest/member/pointsMall/platformPay") @Transactional(rollbackFor = Exception.class) -@Api(tags = "平台支付模块相关接口", description = "PointsMallPlatformPayController") +@Tag(name = "平台支付模块相关接口", description = "PointsMallPlatformPayController") public class PointsMallPlatformPayController { @Autowired @@ -66,7 +67,7 @@ public class PointsMallPlatformPayController { * @return * @author 暹罗 */ - @ApiOperation(value = "使用平台积分支付") + @Operation(summary = "使用平台积分支付") @PostMapping(value = "/byPoints") public BasicResult byPoints(@RequestBody @Validated PlatformPayDto platformPayDto, HttpServletRequest request) { //TODO-PS:但是如果按照微信支付的步骤来,只要某个步骤失败,事务就会回滚--莫非这种就是不能在Controller上添加事务注解的原因? diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallShoppingCartController.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallShoppingCartController.java index c434636..aaf18c6 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallShoppingCartController.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallShoppingCartController.java @@ -13,7 +13,8 @@ import com.siam.package_mall.entity.PointsMallShoppingCart; import com.siam.package_mall.model.example.PointsMallShoppingCartExample; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -23,7 +24,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -33,7 +34,7 @@ @RestController @RequestMapping(value = "/rest/member/pointsMall/shoppingCart") @Transactional(rollbackFor = Exception.class) -@Api(tags = "购物车模块相关接口", description = "PointsMallShoppingCartController") +@Tag(name = "购物车模块相关接口", description = "PointsMallShoppingCartController") public class PointsMallShoppingCartController { @Autowired diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallWxPayService.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallWxPayService.java index 15d7a56..1de7674 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallWxPayService.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/controller/member/PointsMallWxPayService.java @@ -25,10 +25,11 @@ import org.apache.http.util.EntityUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Service; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import javax.net.ssl.SSLContext; import java.io.IOException; import java.io.InputStream; @@ -54,6 +55,7 @@ public class PointsMallWxPayService { @Autowired private WxPublicPlatformNotifyService wxPublicPlatformNotifyService; + @Lazy @Resource(name = "pointsMallOrderServiceImpl") private PointsMallOrderService pointsMallOrderService; diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/feign/PointsMallOrderFeignProvider.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/feign/PointsMallOrderFeignProvider.java index 4a7cedd..264d3ff 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/feign/PointsMallOrderFeignProvider.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/feign/PointsMallOrderFeignProvider.java @@ -7,7 +7,7 @@ import com.siam.package_mall.service.PointsMallOrderService; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import java.util.Date; /** diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/mqConsumer/PointsMallGoodsConsumer.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/mqConsumer/PointsMallGoodsConsumer.java index 606960b..d6c913a 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/mqConsumer/PointsMallGoodsConsumer.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/mqConsumer/PointsMallGoodsConsumer.java @@ -6,7 +6,7 @@ //import org.springframework.beans.factory.annotation.Autowired; //import org.springframework.stereotype.Component; // -//import javax.annotation.PostConstruct; +//import jakarta.annotation.PostConstruct; // //@Component //public class PointsMallGoodsConsumer { diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/mqConsumer/PointsMallOrderConsumer.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/mqConsumer/PointsMallOrderConsumer.java index 4d8dda5..974c868 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/mqConsumer/PointsMallOrderConsumer.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/mqConsumer/PointsMallOrderConsumer.java @@ -11,7 +11,7 @@ import org.apache.rocketmq.spring.core.RocketMQListener; import org.springframework.stereotype.Component; -import javax.annotation.Resource; +import jakarta.annotation.Resource; @Slf4j @Component diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/service_impl/PointsMallOrderLogisticsServiceImpl.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/service_impl/PointsMallOrderLogisticsServiceImpl.java index abbda29..48ec2ad 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/service_impl/PointsMallOrderLogisticsServiceImpl.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/service_impl/PointsMallOrderLogisticsServiceImpl.java @@ -12,9 +12,10 @@ import com.siam.package_mall.service.PointsMallOrderLogisticsService; import com.siam.package_mall.service.PointsMallOrderService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -29,6 +30,7 @@ public class PointsMallOrderLogisticsServiceImpl implements PointsMallOrderLogis @Autowired private AliyunExpressUtils aliyunExpressUtils; + @Lazy @Resource(name = "pointsMallOrderServiceImpl") private PointsMallOrderService orderService; diff --git a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/service_impl/PointsMallOrderServiceImpl.java b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/service_impl/PointsMallOrderServiceImpl.java index 99cc592..30bfceb 100644 --- a/siam-mall/mall-provider/src/main/java/com/siam/package_mall/service_impl/PointsMallOrderServiceImpl.java +++ b/siam-mall/mall-provider/src/main/java/com/siam/package_mall/service_impl/PointsMallOrderServiceImpl.java @@ -39,6 +39,7 @@ import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Lazy; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; @@ -85,6 +86,7 @@ public class PointsMallOrderServiceImpl implements PointsMallOrderService { @Autowired private MemberInviteRelationFeignApi memberInviteRelationFeignApi; + @Lazy @Autowired private PointsMallOrderLogisticsService orderLogisticsService; @@ -100,6 +102,7 @@ public class PointsMallOrderServiceImpl implements PointsMallOrderService { @Autowired private PointsMallOrderRefundProcessService orderRefundProcessService; + @Lazy @Autowired private PointsMallWxPayService pointsMallWxPayService; diff --git a/siam-mall/mall-provider/src/main/resources/application-local.yml b/siam-mall/mall-provider/src/main/resources/application-local.yml index 31547a5..dc4a723 100644 --- a/siam-mall/mall-provider/src/main/resources/application-local.yml +++ b/siam-mall/mall-provider/src/main/resources/application-local.yml @@ -5,9 +5,9 @@ server: spring: #mysql datasource: - url: jdbc:mysql://127.0.0.1:3306/siam_cloud_mall?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8 + url: jdbc:mysql://127.0.0.1:3306/siam_cloud_mall?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true username: root - password: root + password: 123456 #thymeleaf thymeleaf: @@ -61,6 +61,18 @@ spring: application: name: mall-siam + # Nacos注册中心/配置中心 + cloud: + nacos: + discovery: + server-addr: 127.0.0.1:8848 + config: + server-addr: 127.0.0.1:8848 + file-extension: yaml + config: + import: + - optional:nacos:${spring.application.name}-local.yaml + #配置文件上传大小限制 servlet: multipart: @@ -91,15 +103,15 @@ spring: ds0: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver - url: jdbc:mysql://127.0.0.1:3306/siam_cloud_mall_0?characterEncoding=utf-8&useUnicode=true&useSSL=true + url: jdbc:mysql://127.0.0.1:3306/siam_cloud_mall_0?characterEncoding=utf-8&useUnicode=true&useSSL=true&allowPublicKeyRetrieval=true username: root - password: root + password: 123456 ds1: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver - url: jdbc:mysql://127.0.0.1:3306/siam_cloud_mall_1?characterEncoding=utf-8&useUnicode=true&useSSL=true + url: jdbc:mysql://127.0.0.1:3306/siam_cloud_mall_1?characterEncoding=utf-8&useUnicode=true&useSSL=true&allowPublicKeyRetrieval=true username: root - password: root + password: 123456 props: sql: show: true #是否显示sharding-jdbc的sql路由 @@ -179,17 +191,7 @@ mybatis-plus: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl -#eureka配置 -eureka: - client: - service-url: - defaultZone: http://127.0.0.1:9000/eureka/ - register-with-eureka: true - fetch-registry: true - instance: - #配置使用ip地址来注册(默认是主机名称) - prefer-ip-address: true - #心跳检测暂时不配置 +# Nacos注册中心/配置中心 feign: #feign内部服务调用超时配置-第二种 @@ -222,24 +224,31 @@ rocketmq: # Seata Config seata: - application-id: mall-service + application-id: ${spring.application.name} tx-service-group: my_test_tx_group service: vgroup-mapping: - # 此处配置对应Server端配置registry.eureka.application的值 my_test_tx_group: default registry: - type: eureka - eureka: - service-url: http://127.0.0.1:9000/eureka/ - weight: 1 + type: nacos + nacos: + application: seata-server + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public + config: + type: nacos + nacos: + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public #springboot admin相关配置 management: endpoints: web: exposure: - include: "*" #'prometheus,health' + include: "health,prometheus,info" exclude: "shutdown" base-path: /actuator endpoint: @@ -264,6 +273,8 @@ management: enabled: false elasticsearch: enabled: false + mail: + enabled: false #日志配置 logging: diff --git a/siam-mall/pom.xml b/siam-mall/pom.xml index a1129ce..b99f934 100644 --- a/siam-mall/pom.xml +++ b/siam-mall/pom.xml @@ -31,8 +31,6 @@ UTF-8 - 1.8 - 1.8 \ No newline at end of file diff --git a/siam-merchant/merchant-api/pom.xml b/siam-merchant/merchant-api/pom.xml index 20c47d9..2e4d623 100644 --- a/siam-merchant/merchant-api/pom.xml +++ b/siam-merchant/merchant-api/pom.xml @@ -16,8 +16,6 @@ UTF-8 - 1.8 - 1.8 @@ -37,7 +35,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 exec diff --git a/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/entity/Merchant.java b/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/entity/Merchant.java index c1b5b54..bc89a74 100644 --- a/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/entity/Merchant.java +++ b/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/entity/Merchant.java @@ -3,60 +3,59 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.math.BigDecimal; import java.util.Date; @TableName("tb_merchant") -@ApiModel(value = "商家表") + @Schema(description= "商家表") public class Merchant { - @ApiModelProperty(notes = "主键id") + @Schema(description = "主键id") @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "门店信息id") + @Schema(description = "门店信息id") private Integer shopId; - @ApiModelProperty(notes = "用户名称") + @Schema(description = "用户名称") private String username; - @ApiModelProperty(notes = "手机号码") + @Schema(description = "手机号码") private String mobile; - @ApiModelProperty(notes = "用户密码") + @Schema(description = "用户密码") private String password; - @ApiModelProperty(notes = "密码加盐") + @Schema(description = "密码加盐") private String passwordSalt; - @ApiModelProperty(notes = "昵称") + @Schema(description = "昵称") private String nickname; - @ApiModelProperty(notes = "权限") + @Schema(description = "权限") private String roles; - @ApiModelProperty(notes = "头像") + @Schema(description = "头像") private String headImg; - @ApiModelProperty(notes = "性别") + @Schema(description = "性别") private Integer sex; - @ApiModelProperty(notes = "邮箱") + @Schema(description = "邮箱") private String email; - @ApiModelProperty(notes = "证件类型") + @Schema(description = "证件类型") private String certificateType; - @ApiModelProperty(notes = "证件照片") + @Schema(description = "证件照片") private String certificateImg; - @ApiModelProperty(notes = "是否禁用 0=启用 1=禁用") + @Schema(description = "是否禁用 0=启用 1=禁用") private Boolean isDisabled; - @ApiModelProperty(notes = "是否删除 0=正常 1=删除") + @Schema(description = "是否删除 0=正常 1=删除") private Boolean isDeleted; private Integer auditStatus; diff --git a/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/entity/Shop.java b/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/entity/Shop.java index 30c6634..c613052 100644 --- a/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/entity/Shop.java +++ b/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/entity/Shop.java @@ -5,7 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.google.gson.annotations.SerializedName; -import io.swagger.annotations.ApiModel; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; @@ -14,7 +14,7 @@ @Data @TableName("tb_shop") -@ApiModel(value = "门店表") + @Schema(description= "门店表") public class Shop { /* ##################################### START 扩展字段 #################################### */ diff --git a/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/model/param/MerchantWithdrawRecordParam.java b/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/model/param/MerchantWithdrawRecordParam.java index 8420244..b2e1dcd 100644 --- a/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/model/param/MerchantWithdrawRecordParam.java +++ b/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/model/param/MerchantWithdrawRecordParam.java @@ -6,7 +6,7 @@ import lombok.Data; import org.hibernate.validator.constraints.Range; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; import java.math.BigDecimal; import java.util.Date; diff --git a/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/model/param/ShopChangeRecordParam.java b/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/model/param/ShopChangeRecordParam.java index a6e2a55..212901a 100644 --- a/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/model/param/ShopChangeRecordParam.java +++ b/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/model/param/ShopChangeRecordParam.java @@ -5,7 +5,7 @@ import lombok.Data; import org.hibernate.validator.constraints.Range; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; import java.util.Date; @Data diff --git a/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/model/param/ShopParam.java b/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/model/param/ShopParam.java index df50a43..fc73b22 100644 --- a/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/model/param/ShopParam.java +++ b/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/model/param/ShopParam.java @@ -3,11 +3,11 @@ import com.siam.package_common.model.valid_group.ValidGroupOfAudit; import com.siam.package_common.model.valid_group.ValidGroupOfId; import com.siam.package_merchant.entity.Shop; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import org.hibernate.validator.constraints.Range; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; import java.util.Date; import java.util.List; diff --git a/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/util/HttpContext.java b/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/util/HttpContext.java index 35d5f94..6007180 100644 --- a/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/util/HttpContext.java +++ b/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/util/HttpContext.java @@ -3,8 +3,8 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.Map; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; diff --git a/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/util/TokenUtil.java b/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/util/TokenUtil.java index cebd36d..9a79890 100644 --- a/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/util/TokenUtil.java +++ b/siam-merchant/merchant-api/src/main/java/com/siam/package_merchant/util/TokenUtil.java @@ -6,9 +6,9 @@ import com.siam.package_common.util.ToolUtil; import com.siam.package_merchant.entity.Merchant; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; /** * Token工具类 diff --git a/siam-merchant/merchant-provider/pom.xml b/siam-merchant/merchant-provider/pom.xml index cb5fecf..c933ddb 100644 --- a/siam-merchant/merchant-provider/pom.xml +++ b/siam-merchant/merchant-provider/pom.xml @@ -16,8 +16,6 @@ UTF-8 - 1.8 - 1.8 @@ -77,51 +75,40 @@ 1.1 - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - 2.1.2.RELEASE - - - + com.alibaba.cloud - spring-cloud-starter-alibaba-seata - 2021.1 - - - io.seata - seata-spring-boot-starter - - + spring-cloud-starter-alibaba-nacos-discovery + - io.seata - seata-spring-boot-starter - 1.3.0 + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config org.springframework.boot spring-boot-starter-actuator - 2.3.3.RELEASE io.micrometer micrometer-registry-prometheus - 1.5.4 net.logstash.logback logstash-logback-encoder - 6.6 + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui @@ -132,7 +119,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 com.siam.package_merchant.MerchantApplication diff --git a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/MerchantApplication.java b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/MerchantApplication.java index af33f77..0a5b279 100644 --- a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/MerchantApplication.java +++ b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/MerchantApplication.java @@ -3,12 +3,17 @@ import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @EnableFeignClients("com.siam") -@EnableEurekaClient -@SpringBootApplication(scanBasePackages = "com.siam") +@EnableDiscoveryClient +@SpringBootApplication(scanBasePackages = "com.siam", exclude = { + MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class +}) @MapperScan(basePackages = {"com.siam.**.mapper"}) public class MerchantApplication { diff --git a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/config/MybatisPlusConfig.java b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/config/MybatisPlusConfig.java index 3d1407c..ba33152 100644 --- a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/config/MybatisPlusConfig.java +++ b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/config/MybatisPlusConfig.java @@ -1,6 +1,8 @@ package com.siam.package_merchant.config; -import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -19,8 +21,11 @@ public class MybatisPlusConfig { * 分页插件 */ @Bean - public PaginationInterceptor paginationInterceptor() { - return new PaginationInterceptor(); + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); + interceptor.addInnerInterceptor(paginationInnerInterceptor); + return interceptor; } } \ No newline at end of file diff --git a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/config/Swagger2Config.java b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/config/Swagger2Config.java deleted file mode 100644 index 6ccdaf2..0000000 --- a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/config/Swagger2Config.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.siam.package_merchant.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; - -@Configuration -@EnableSwagger2 -public class Swagger2Config { - - @Bean - public Docket createRestApi() { - return new Docket(DocumentationType.SWAGGER_2) - .apiInfo(apiInfo()) - .select() - .apis(RequestHandlerSelectors.basePackage("com.siam"))//扫描包路径 - .paths(PathSelectors.any()) - .build(); - } - - // 构建api文档的详细信息函数,注意这里的注解引用的是哪个 - private ApiInfo apiInfo() { - return new ApiInfoBuilder() - .title("暹罗外卖-商家服务接口文档")//页面标题 - .description("")//描述 - .version("1.0")//版本号 - .build(); - } -} \ No newline at end of file diff --git a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminMerchantBillingRecordController.java b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminMerchantBillingRecordController.java index c5f4b8d..c12f961 100644 --- a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminMerchantBillingRecordController.java +++ b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminMerchantBillingRecordController.java @@ -6,8 +6,9 @@ import com.siam.package_merchant.service.MerchantBillingRecordService; import com.siam.package_merchant.service.MerchantService; import com.siam.package_merchant.service.MerchantTokenService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -21,7 +22,7 @@ @RestController @RequestMapping(value = "/rest/admin/merchantBillingRecord") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台商家账单记录模块相关接口", description = "AdminMerchantBillingRecordController") +@Tag(name = "后台商家账单记录模块相关接口", description = "AdminMerchantBillingRecordController") public class AdminMerchantBillingRecordController { @Autowired @@ -30,14 +31,14 @@ public class AdminMerchantBillingRecordController { @Autowired private MerchantService merchantService; - @ApiOperation(value = "商家账单记录列表") + @Operation(summary = "商家账单记录列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) MerchantBillingRecordParam param) { Page> page = merchantBillingRecordService.getListByPageJoinShop(param); return BasicResult.success(page); } - @ApiOperation(value = "商家账单记录-统计金额") + @Operation(summary = "商家账单记录-统计金额") @PostMapping(value = "/statisticalAmount") public BasicResult statisticalAmount(@RequestBody @Validated(value = {}) MerchantBillingRecordParam param) { Map map = merchantBillingRecordService.statisticalAmount(param); diff --git a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminMerchantController.java b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminMerchantController.java index ec03944..a08d015 100644 --- a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminMerchantController.java +++ b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminMerchantController.java @@ -1,7 +1,8 @@ package com.siam.package_merchant.controller.admin; import com.siam.package_merchant.service.MerchantService; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RequestMapping; @@ -10,7 +11,7 @@ @RestController @RequestMapping(value = "/rest/admin/merchant") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台商家账号模块相关接口", description = "AdminMerchantController") +@Tag(name = "后台商家账号模块相关接口", description = "AdminMerchantController") public class AdminMerchantController { @Autowired diff --git a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminMerchantWithdrawRecordController.java b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminMerchantWithdrawRecordController.java index 4301477..eac72dd 100644 --- a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminMerchantWithdrawRecordController.java +++ b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminMerchantWithdrawRecordController.java @@ -7,8 +7,9 @@ import com.siam.package_common.model.valid_group.ValidGroupOfId; import com.siam.package_merchant.model.param.MerchantWithdrawRecordParam; import com.siam.package_merchant.service.MerchantWithdrawRecordService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -22,20 +23,20 @@ @RestController @RequestMapping(value = "/rest/admin/merchantWithdrawRecord") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台商家提现记录模块相关接口", description = "AdminMerchantWithdrawRecordController") +@Tag(name = "后台商家提现记录模块相关接口", description = "AdminMerchantWithdrawRecordController") public class AdminMerchantWithdrawRecordController { @Autowired private MerchantWithdrawRecordService merchantWithdrawRecordService; - @ApiOperation(value = "商家提现记录列表") + @Operation(summary = "商家提现记录列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) MerchantWithdrawRecordParam param){ Page> page = merchantWithdrawRecordService.getListByPageJoinShop(param); return BasicResult.success(page); } - @ApiOperation(value = "商家提现记录-统计金额") + @Operation(summary = "商家提现记录-统计金额") @PostMapping(value = "/statisticalAmount") public BasicResult statisticalAmount(@RequestBody @Validated(value = {}) MerchantWithdrawRecordParam param){ Map map = merchantWithdrawRecordService.statisticalAmount(param); diff --git a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminShopChangeRecordController.java b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminShopChangeRecordController.java index ee18258..358e478 100644 --- a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminShopChangeRecordController.java +++ b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminShopChangeRecordController.java @@ -16,8 +16,9 @@ import com.siam.package_common.model.valid_group.ValidGroupOfId; import com.siam.package_merchant.service.ShopChangeRecordService; import com.siam.package_merchant.service.ShopService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -27,14 +28,14 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.Date; import java.util.Map; @RestController @RequestMapping(value = "/rest/admin/shopChangeRecord") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台门店重要信息变更记录模块相关接口", description = "AdminShopChangeRecordController") +@Tag(name = "后台门店重要信息变更记录模块相关接口", description = "AdminShopChangeRecordController") public class AdminShopChangeRecordController { @Autowired private ShopChangeRecordService shopChangeRecordService; @@ -48,7 +49,7 @@ public class AdminShopChangeRecordController { @Autowired private ShopService shopService; - @ApiOperation(value = "门店重要信息变更记录列表") + @Operation(summary = "门店重要信息变更记录列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) ShopChangeRecord shopChangeRecord, HttpServletRequest request){ BasicData basicResult = new BasicData(); diff --git a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminShopController.java b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminShopController.java index 3ed7012..d444e1a 100644 --- a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminShopController.java +++ b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/admin/AdminShopController.java @@ -20,8 +20,9 @@ import com.siam.package_user.entity.Member; import com.siam.package_user.feign.MemberFeignApi; import com.siam.package_user.model.param.MemberParam; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -36,7 +37,7 @@ @RestController @RequestMapping(value = "/rest/admin/shop") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台门店模块相关接口", description = "AdminShopController") +@Tag(name = "后台门店模块相关接口", description = "AdminShopController") public class AdminShopController { @Autowired @@ -48,7 +49,7 @@ public class AdminShopController { @Autowired private MemberFeignApi memberFeignApi; - @ApiOperation(value = "门店信息列表") + @Operation(summary = "门店信息列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) Shop shop){ BasicData basicResult = new BasicData(); @@ -56,7 +57,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) Shop shop){ return BasicResult.success(page); } - @ApiOperation(value = "新增门店信息") + @Operation(summary = "新增门店信息") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) Shop shop){ BasicResult basicResult = new BasicResult(); @@ -70,7 +71,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) Shop shop){ } @AdminPermission - @ApiOperation(value = "修改门店信息") + @Operation(summary = "修改门店信息") @PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) Shop shop, String memberMobile) throws IOException { BasicResult basicResult = new BasicResult(); @@ -116,7 +117,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) Shop shop, String } @AdminPermission - @ApiOperation(value = "删除门店信息") + @Operation(summary = "删除门店信息") @DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) Shop param){ BasicResult basicResult = new BasicResult(); @@ -124,7 +125,7 @@ public BasicResult delete(@RequestBody @Validated(value = {}) Shop param){ //判断菜单下面有关联商品,则不能删除 LambdaQueryWrapper wrapper = new LambdaQueryWrapper(); wrapper.eq(Shop::getId, id); - int result = shopService.count(wrapper); + long result = shopService.count(wrapper); if(result == 0){ basicResult.setSuccess(false); basicResult.setCode(BasicResultCode.ERR); diff --git a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/member/ShopController.java b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/member/ShopController.java index e26d42e..3342f28 100644 --- a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/member/ShopController.java +++ b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/member/ShopController.java @@ -29,7 +29,8 @@ import com.siam.package_promotion.model.vo.PromotionVo; import com.siam.package_util.entity.Setting; import com.siam.package_util.feign.SettingFeignApi; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -48,7 +49,7 @@ @RestController @RequestMapping(value = "/rest/shop") @Transactional(rollbackFor = Exception.class) -@Api(tags = "门店模块相关接口", description = "ShopController") +@Tag(name = "门店模块相关接口", description = "ShopController") public class ShopController { @Autowired diff --git a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/member/WxLoginController.java b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/member/WxLoginController.java index 07ea1b6..b6bee76 100644 --- a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/member/WxLoginController.java +++ b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/member/WxLoginController.java @@ -8,7 +8,8 @@ import com.siam.package_weixin_basic.config.WxEncrypted; import com.siam.package_weixin_basic.config.WxSession; import com.siam.package_weixin_basic.util.WxdecodeUtils; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.http.HttpMethod; @@ -90,7 +91,7 @@ public WxEncrypted getWxUserInfo(String code, String iv, String encryptedData) t return null; } - @ApiOperation(value = "获取微信手机号") + @Operation(summary = "获取微信手机号") @PostMapping(value = "/getWxPhone") public BasicResult getWxPhone(@RequestBody WxCode wxCode) throws Exception { BasicData basicResult = new BasicData(); diff --git a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantBillingRecordController.java b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantBillingRecordController.java index 53df919..b62dbb8 100644 --- a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantBillingRecordController.java +++ b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantBillingRecordController.java @@ -5,8 +5,9 @@ import com.siam.package_merchant.entity.MerchantBillingRecord; import com.siam.package_merchant.model.param.MerchantBillingRecordParam; import com.siam.package_merchant.service.MerchantBillingRecordService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -20,20 +21,20 @@ @RestController @RequestMapping(value = "/rest/merchant/merchantBillingRecord") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家账单记录模块相关接口", description = "merchantBillingRecordController") +@Tag(name = "商家账单记录模块相关接口", description = "merchantBillingRecordController") public class MerchantBillingRecordController { @Autowired private MerchantBillingRecordService merchantBillingRecordService; - @ApiOperation(value = "商家账单记录列表") + @Operation(summary = "商家账单记录列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) MerchantBillingRecordParam param) { Page page = merchantBillingRecordService.getListByPage(param); return BasicResult.success(page); } - @ApiOperation(value = "商家账单记录-统计金额") + @Operation(summary = "商家账单记录-统计金额") @PostMapping(value = "/statisticalAmount") public BasicResult statisticalAmount(@RequestBody @Validated(value = {}) MerchantBillingRecordParam param) { Map map = merchantBillingRecordService.statisticalAmount(param); diff --git a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantController.java b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantController.java index 586aed4..5fe66ad 100644 --- a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantController.java +++ b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantController.java @@ -5,7 +5,8 @@ import com.siam.package_merchant.model.param.MerchantParam; import com.siam.package_merchant.model.result.MerchantResult; import com.siam.package_merchant.service.MerchantService; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -14,7 +15,7 @@ @RestController @RequestMapping(value = "/rest/merchant") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台商家账号模块相关接口", description = "MerchantController") +@Tag(name = "后台商家账号模块相关接口", description = "MerchantController") public class MerchantController { @Autowired diff --git a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantShopChangeRecordController.java b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantShopChangeRecordController.java index 46828d3..fd9d124 100644 --- a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantShopChangeRecordController.java +++ b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantShopChangeRecordController.java @@ -9,8 +9,11 @@ import com.siam.package_merchant.service.ShopChangeRecordService; import com.siam.package_user.util.TokenUtil; import com.siam.package_util.feign.SettingFeignApi; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -20,13 +23,13 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; @Slf4j @RestController @RequestMapping(value = "/rest/merchant/shopChangeRecord") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端门店重要信息变更记录模块相关接口", description = "ShopChangeRecordController") +@Tag(name = "商家端门店重要信息变更记录模块相关接口", description = "ShopChangeRecordController") public class MerchantShopChangeRecordController { @Autowired private ShopChangeRecordService shopChangeRecordService; @@ -40,7 +43,7 @@ public class MerchantShopChangeRecordController { @Autowired private MerchantSessionManager merchantSessionManager; - @ApiOperation(value = "门店重要信息变更记录列表") + @Operation(summary = "门店重要信息变更记录列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) ShopChangeRecord shopChangeRecord, HttpServletRequest request){ BasicData basicResult = new BasicData(); @@ -54,18 +57,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) ShopChangeRecord sho return BasicResult.success(page); } - /*@ApiOperation(value = "新增门店重要信息变更记录") - @ApiImplicitParams({ - @ApiImplicitParam(name = "name", value = "门店重要信息变更记录名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "mainImage", value = "门店重要信息变更记录主图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "description", value = "门店重要信息变更记录描述", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "unit", value = "采购单位", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "采购单价", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stock", value = "库存", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stockLowerLimit", value = "库存过低线/库存下限", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stockUpperLimit", value = "库存超出线/库存上限", required = true, paramType = "query", dataType = "BigDecimal"), - }) - @PostMapping(value = "/insert") + /*@Operation(summary = "新增门店重要信息变更记录")@PostMapping(value = "/insert") public BasicResult insert(ShopChangeRecord shopChangeRecord, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); @@ -131,19 +123,7 @@ public BasicResult insert(ShopChangeRecord shopChangeRecord, HttpServletRequest }*/ - /*@ApiOperation(value = "修改门店重要信息变更记录") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "门店重要信息变更记录主键id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "门店重要信息变更记录名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "mainImage", value = "门店重要信息变更记录主图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "description", value = "门店重要信息变更记录描述", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "unit", value = "采购单位", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "采购单价", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stock", value = "库存", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stockLowerLimit", value = "库存过低线/库存下限", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stockUpperLimit", value = "库存超出线/库存上限", required = true, paramType = "query", dataType = "BigDecimal"), - }) - @PutMapping(value = "/update") + /*@Operation(summary = "修改门店重要信息变更记录")@PutMapping(value = "/update") public BasicResult update(ShopChangeRecord shopChangeRecord, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); @@ -180,11 +160,7 @@ public BasicResult update(ShopChangeRecord shopChangeRecord, HttpServletRequest }*/ - /*@ApiOperation(value = "删除门店重要信息变更记录") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "门店重要信息变更记录主键id", required = true, paramType = "query", dataType = "int") - }) - @DeleteMapping(value = "/delete") + /*@Operation(summary = "删除门店重要信息变更记录")@DeleteMapping(value = "/delete") public BasicResult delete(int id, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); diff --git a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantShopController.java b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantShopController.java index bd4c747..5b625c2 100644 --- a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantShopController.java +++ b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantShopController.java @@ -15,10 +15,8 @@ import com.siam.package_merchant.entity.ShopChangeRecord; import com.siam.package_merchant.service.ShopChangeRecordService; import com.siam.package_merchant.service.ShopService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -28,13 +26,13 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.Date; @RestController @RequestMapping(value = "/rest/merchant/shop") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端门店模块相关接口", description = "MerchantShopController") +@Tag(name = "商家端门店模块相关接口", description = "MerchantShopController") public class MerchantShopController { @Autowired @@ -43,32 +41,17 @@ public class MerchantShopController { @Autowired private ShopService shopService; -// @Autowired -// private MerchantService merchantService; - @Autowired private ShopChangeRecordService shopChangeRecordService; @Autowired private SettingFeignApi settingFeignApi; - @ApiOperation(value = "申请开店-提交门店信息") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "门店管理表主键id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "code", value = "门店编码", required = true, paramType = "query", dataType = "String"), - @ApiImplicitParam(name = "name", value = "门店名称", required = true, paramType = "query", dataType = "String"), - @ApiImplicitParam(name = "distance", value = "距离", required = false, paramType = "query", dataType = "String"), - @ApiImplicitParam(name = "province", value = "省份", required = true, paramType = "query", dataType = "String"), - @ApiImplicitParam(name = "city", value = "城市", required = true, paramType = "query", dataType = "String"), - @ApiImplicitParam(name = "area", value = "区域", required = true, paramType = "query", dataType = "String"), - @ApiImplicitParam(name = "street", value = "街道/详细收货地址", required = false, paramType = "query", dataType = "String"), - @ApiImplicitParam(name = "isDisabled", value = "是否禁用 0=启用 1=禁用", required = true, paramType = "query", dataType = "String"), - }) + @Operation(summary = "申请开店-提交门店信息") @PostMapping(value = "/apply") public BasicResult apply(@RequestBody @Validated(value = {}) Shop shop, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); - //获取当前登录用户绑定的门店编号 Merchant loginMerchant = merchantSessionManager.getSession(TokenUtil.getToken()); if(loginMerchant.getAuditStatus() == Quantity.INT_2){ @@ -82,7 +65,6 @@ public BasicResult apply(@RequestBody @Validated(value = {}) Shop shop, HttpServ Setting setting = settingFeignApi.selectCurrent().getData(); shop.setStartDeliveryPrice(setting.getStartDeliveryPrice()); - //修改申请开店的门店信息 shop.setUpdateTime(new Date()); shopService.updateByPrimaryKeySelective(shop); @@ -92,7 +74,7 @@ public BasicResult apply(@RequestBody @Validated(value = {}) Shop shop, HttpServ return basicResult; } - @ApiOperation(value = "获取登录商家账号的开店信息") + @Operation(summary = "获取登录商家账号的开店信息") @PostMapping(value = "/getLoginMerchantShopInfo") public BasicResult getLoginMerchantShopInfo(@RequestBody @Validated(value = {}) Shop param){ BasicData basicResult = new BasicData(); @@ -110,18 +92,11 @@ public BasicResult getLoginMerchantShopInfo(@RequestBody @Validated(value = {}) return basicResult; } - /** - * 修改门店信息 - * - * @return - * @author 暹罗 - */ @MerchantPermission @PostMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) Shop shop, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); - //获取当前登录用户绑定的门店编号 Merchant loginMerchant = merchantSessionManager.getSession(TokenUtil.getToken()); if (loginMerchant.getShopId() != shop.getId()){ @@ -133,8 +108,6 @@ public BasicResult update(@RequestBody @Validated(value = {}) Shop shop, HttpSer throw new StoneCustomerException("该店铺信息不存在"); } - //TODO-有些信息不能直接修改,需要管理员审核 - shop.setUpdateTime(new Date()); shopService.updateByPrimaryKeySelective(shop); @@ -144,17 +117,10 @@ public BasicResult update(@RequestBody @Validated(value = {}) Shop shop, HttpSer return basicResult; } - /** - * 申请变更门店重要信息 - * - * @return - * @author 暹罗 - */ @PostMapping(value = "/applyChangeImportantData") public BasicResult applyChangeImportantData(@RequestBody @Validated(value = {}) ShopChangeRecord shopChangeRecord, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); - //获取当前登录用户绑定的门店编号 Merchant loginMerchant = merchantSessionManager.getSession(TokenUtil.getToken()); if (loginMerchant.getShopId() != shopChangeRecord.getShopId()){ @@ -166,17 +132,14 @@ public BasicResult applyChangeImportantData(@RequestBody @Validated(value = {}) throw new StoneCustomerException("该店铺信息不存在"); } - //获取变更内容 String applyChangeContent = getApplyChangeContent(dbShop, shopChangeRecord); if(StringUtils.isBlank(applyChangeContent)){ throw new StoneCustomerException("没有变更信息,提交失败"); } shopChangeRecord.setApplyChangeContent(applyChangeContent); - //如果申请记录为审核中,则进行修改操作,否则进行新增操作 ShopChangeRecord dbShopChangeRecord = shopChangeRecordService.selectLastestByShopId(shopChangeRecord.getShopId()); if(dbShopChangeRecord==null || dbShopChangeRecord.getAuditStatus()==Quantity.INT_2 || dbShopChangeRecord.getAuditStatus()==Quantity.INT_3){ - //新增操作 shopChangeRecord.setAuditStatus(Quantity.INT_1); shopChangeRecord.setAuditReason(null); shopChangeRecord.setAuditTime(null); @@ -184,7 +147,6 @@ public BasicResult applyChangeImportantData(@RequestBody @Validated(value = {}) shopChangeRecord.setUpdateTime(new Date()); shopChangeRecordService.insertSelective(shopChangeRecord); }else{ - //修改操作 shopChangeRecord.setId(dbShopChangeRecord.getId()); shopChangeRecord.setAuditStatus(null); shopChangeRecord.setAuditReason(null); @@ -193,9 +155,6 @@ public BasicResult applyChangeImportantData(@RequestBody @Validated(value = {}) shopChangeRecordService.updateByPrimaryKeySelective(shopChangeRecord); } - //TODO-比对有哪些字段进行了修改 - - basicResult.setSuccess(true); basicResult.setCode(BasicResultCode.SUCCESS); basicResult.setMessage("修改成功"); @@ -207,81 +166,53 @@ public String getApplyChangeContent(Shop dbShop, ShopChangeRecord shopChangeReco if(shopChangeRecord.getName()!=null && !shopChangeRecord.getName().equals(dbShop.getName())){ applyChangeContent += "店铺名称、"; } - if(shopChangeRecord.getProvince()!=null && !shopChangeRecord.getProvince().equals(dbShop.getProvince())){ applyChangeContent += "所在省份、"; } - if(shopChangeRecord.getCity()!=null && !shopChangeRecord.getCity().equals(dbShop.getCity())){ applyChangeContent += "所在城市、"; } - if(shopChangeRecord.getArea()!=null && !shopChangeRecord.getArea().equals(dbShop.getArea())){ applyChangeContent += "所在区/县、"; } - if(shopChangeRecord.getStreet()!=null && !shopChangeRecord.getStreet().equals(dbShop.getStreet())){ applyChangeContent += "门店地址、"; } - if(shopChangeRecord.getManagePrimary()!=null && !shopChangeRecord.getManagePrimary().equals(dbShop.getManagePrimary())){ applyChangeContent += "营业类目、"; } - - /*if(shopChangeRecord.getManageMinor()!=null && !shopChangeRecord.getManageMinor().equals(dbShop.getManageMinor())){ - applyChangeContent += "店铺名称、"; - } - - if(shopChangeRecord.getShopImg()!=null && !shopChangeRecord.getShopImg().equals(dbShop.getShopImg())){ - applyChangeContent += "店铺名称、"; - }*/ - if(shopChangeRecord.getShopWithinImg()!=null && !shopChangeRecord.getShopWithinImg().equals(dbShop.getShopWithinImg())){ applyChangeContent += "店内照片、"; } - if(shopChangeRecord.getShopLogoImg()!=null && !shopChangeRecord.getShopLogoImg().equals(dbShop.getShopLogoImg())){ applyChangeContent += "门店头像、"; } - - /*if(shopChangeRecord.getContactRealname()!=null && !shopChangeRecord.getContactRealname().equals(dbShop.getContactRealname())){ - applyChangeContent += "店铺名称、"; - }*/ - if(shopChangeRecord.getContactPhone()!=null && !shopChangeRecord.getContactPhone().equals(dbShop.getContactPhone())){ applyChangeContent += "联系电话、"; } - if(shopChangeRecord.getAnnouncement()!=null && !shopChangeRecord.getAnnouncement().equals(dbShop.getAnnouncement())){ applyChangeContent += "门店公告、"; } - if(shopChangeRecord.getBriefIntroduction()!=null && !shopChangeRecord.getBriefIntroduction().equals(dbShop.getBriefIntroduction())){ applyChangeContent += "门店简介、"; } - if(shopChangeRecord.getBusinessLicense()!=null && !shopChangeRecord.getBusinessLicense().equals(dbShop.getBusinessLicense())){ applyChangeContent += "营业执照、"; } - if(shopChangeRecord.getIdCardFrontSide()!=null && !shopChangeRecord.getIdCardFrontSide().equals(dbShop.getIdCardFrontSide())){ applyChangeContent += "身份证正面、"; } - if(shopChangeRecord.getIdCardBackSide()!=null && !shopChangeRecord.getIdCardBackSide().equals(dbShop.getIdCardBackSide())){ applyChangeContent += "身份证反面、"; } - if(shopChangeRecord.getHouseNumber()!=null && !shopChangeRecord.getHouseNumber().equals(dbShop.getHouseNumber())){ applyChangeContent += "门牌号、"; } - if(shopChangeRecord.getLongitude()!=null && dbShop.getLongitude()==null){ applyChangeContent += "经度、"; }else if(shopChangeRecord.getLongitude()!=null && dbShop.getLongitude()!=null && shopChangeRecord.getLongitude().compareTo(dbShop.getLongitude())!=0){ applyChangeContent += "经度、"; } - if(shopChangeRecord.getLatitude()!=null && dbShop.getLatitude()==null){ applyChangeContent += "纬度、"; }else if(shopChangeRecord.getLatitude()!=null && dbShop.getLatitude()!=null && shopChangeRecord.getLatitude().compareTo(dbShop.getLatitude())!=0){ @@ -289,7 +220,6 @@ public String getApplyChangeContent(Shop dbShop, ShopChangeRecord shopChangeReco } applyChangeContent = applyChangeContent != "" ? applyChangeContent.substring(0, applyChangeContent.length()-1) : applyChangeContent; - return applyChangeContent; } -} \ No newline at end of file +} diff --git a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantWithdrawRecordController.java b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantWithdrawRecordController.java index 6a50d0c..cfd6401 100644 --- a/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantWithdrawRecordController.java +++ b/siam-merchant/merchant-provider/src/main/java/com/siam/package_merchant/controller/merchant/MerchantWithdrawRecordController.java @@ -6,8 +6,11 @@ import com.siam.package_merchant.model.param.MerchantWithdrawRecordParam; import com.siam.package_merchant.service.MerchantBillingRecordService; import com.siam.package_merchant.service.MerchantWithdrawRecordService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -23,7 +26,7 @@ @RestController @RequestMapping(value = "/rest/merchant/merchantWithdrawRecord") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端商家提现记录模块相关接口", description = "MerchantWithdrawRecordController") +@Tag(name = "商家端商家提现记录模块相关接口", description = "MerchantWithdrawRecordController") public class MerchantWithdrawRecordController { @Autowired @@ -32,21 +35,21 @@ public class MerchantWithdrawRecordController { @Autowired private MerchantBillingRecordService merchantBillingRecordService; - @ApiOperation(value = "商家提现记录列表") + @Operation(summary = "商家提现记录列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) MerchantWithdrawRecordParam param) { Page page = merchantWithdrawRecordService.getListByPage(param); return BasicResult.success(page); } - @ApiOperation(value = "商家提现记录-统计金额") + @Operation(summary = "商家提现记录-统计金额") @PostMapping(value = "/statisticalAmount") public BasicResult statisticalAmount(@RequestBody @Validated(value = {}) MerchantWithdrawRecordParam param) { Map map = merchantWithdrawRecordService.statisticalAmount(param); return BasicResult.success(map); } - @ApiOperation(value = "新增商家提现记录") + @Operation(summary = "新增商家提现记录") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) MerchantWithdrawRecordParam param) { merchantWithdrawRecordService.insert(param); @@ -55,19 +58,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) MerchantWithdrawRe - /*@ApiOperation(value = "修改商家提现记录") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商家提现记录主键id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "商家提现记录名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "mainImage", value = "商家提现记录主图", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "description", value = "商家提现记录描述", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "unit", value = "采购单位", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "采购单价", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stock", value = "库存", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stockLowerLimit", value = "库存过低线/库存下限", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "stockUpperLimit", value = "库存超出线/库存上限", required = true, paramType = "query", dataType = "BigDecimal"), - }) - @PutMapping(value = "/update") + /*@Operation(summary = "修改商家提现记录")@PutMapping(value = "/update") public BasicResult update(MerchantWithdrawRecord merchantWithdrawRecord, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); @@ -104,11 +95,7 @@ public BasicResult update(MerchantWithdrawRecord merchantWithdrawRecord, HttpSer }*/ - /*@ApiOperation(value = "删除商家提现记录") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商家提现记录主键id", required = true, paramType = "query", dataType = "int") - }) - @DeleteMapping(value = "/delete") + /*@Operation(summary = "删除商家提现记录")@DeleteMapping(value = "/delete") public BasicResult delete(int id, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); diff --git a/siam-merchant/merchant-provider/src/main/resources/application-local.yml b/siam-merchant/merchant-provider/src/main/resources/application-local.yml index 4dbcd55..742a961 100644 --- a/siam-merchant/merchant-provider/src/main/resources/application-local.yml +++ b/siam-merchant/merchant-provider/src/main/resources/application-local.yml @@ -5,9 +5,9 @@ server: spring: #mysql datasource: - url: jdbc:mysql://127.0.0.1:3306/siam_cloud?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8 + url: jdbc:mysql://127.0.0.1:3306/siam_cloud?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true username: root - password: root + password: 123456 #redis单例模式 redis: @@ -31,6 +31,18 @@ spring: application: name: merchant-siam + # Nacos注册中心/配置中心 + cloud: + nacos: + discovery: + server-addr: 127.0.0.1:8848 + config: + server-addr: 127.0.0.1:8848 + file-extension: yaml + config: + import: + - optional:nacos:${spring.application.name}-local.yaml + jackson: #时间戳统一转换为指定格式 date-format: yyyy/MM/dd HH:mm:ss @@ -90,17 +102,7 @@ mybatis-plus: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl -#eureka配置 -eureka: - client: - service-url: - defaultZone: http://127.0.0.1:9000/eureka/ - register-with-eureka: true - fetch-registry: true - instance: - #配置使用ip地址来注册(默认是主机名称) - prefer-ip-address: true - #心跳检测暂时不配置 +# Nacos注册中心/配置中心 #feign内部服务调用超时配置-第二种 feign: @@ -112,24 +114,31 @@ feign: # Seata Config seata: - application-id: merchant-service + application-id: ${spring.application.name} tx-service-group: my_test_tx_group service: vgroup-mapping: - # 此处配置对应Server端配置registry.eureka.application的值 my_test_tx_group: default registry: - type: eureka - eureka: - service-url: http://127.0.0.1:9000/eureka/ - weight: 1 + type: nacos + nacos: + application: seata-server + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public + config: + type: nacos + nacos: + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public #springboot admin相关配置 management: endpoints: web: exposure: - include: "*" #'prometheus,health' + include: "health,prometheus,info" exclude: "shutdown" base-path: /actuator endpoint: @@ -154,6 +163,8 @@ management: enabled: false elasticsearch: enabled: false + mail: + enabled: false #日志配置 logging: diff --git a/siam-merchant/pom.xml b/siam-merchant/pom.xml index 033ad26..6d68267 100644 --- a/siam-merchant/pom.xml +++ b/siam-merchant/pom.xml @@ -32,8 +32,6 @@ UTF-8 - 1.8 - 1.8 \ No newline at end of file diff --git a/siam-monitor/pom.xml b/siam-monitor/pom.xml index 98c5f61..f081e93 100644 --- a/siam-monitor/pom.xml +++ b/siam-monitor/pom.xml @@ -46,41 +46,42 @@ org.springframework.boot spring-boot-starter-web - 2.6.13 de.codecentric spring-boot-admin-starter-server - 2.6.8 org.springframework.boot spring-boot-starter-security - 2.6.13 cn.hutool hutool-all - 5.6.3 + 5.8.26 org.springframework.boot spring-boot-starter-mail - 2.6.13 - + - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - 3.1.1 + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui @@ -90,7 +91,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 com.siam.MonitorApplication diff --git a/siam-monitor/src/main/java/com/siam/SecuritySecureConfig.java b/siam-monitor/src/main/java/com/siam/SecuritySecureConfig.java index a8c948d..2aae2d5 100644 --- a/siam-monitor/src/main/java/com/siam/SecuritySecureConfig.java +++ b/siam-monitor/src/main/java/com/siam/SecuritySecureConfig.java @@ -1,15 +1,18 @@ package com.siam; import de.codecentric.boot.admin.server.config.AdminServerProperties; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @EnableWebSecurity @Configuration -public class SecuritySecureConfig extends WebSecurityConfigurerAdapter { +public class SecuritySecureConfig { private final String adminContextPath; @@ -17,28 +20,29 @@ public SecuritySecureConfig(AdminServerProperties adminServer) { this.adminContextPath = adminServer.getContextPath(); } - @Override - protected void configure(HttpSecurity http) throws Exception { + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); successHandler.setTargetUrlParameter("redirectTo"); successHandler.setDefaultTargetUrl(adminContextPath + "/"); - http.authorizeRequests() - .antMatchers(adminContextPath + "/login", - adminContextPath + "/assets/**", - adminContextPath + "/manage/**", - adminContextPath + "/actuator/**", - adminContextPath + "/login.html" - ).permitAll() - .anyRequest().authenticated() - .and() - .formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler) - .and() - .logout().logoutUrl(adminContextPath + "/logout") - .and() - .httpBasic() - .and() - .csrf().disable(); - } + http.authorizeHttpRequests(authz -> authz + .requestMatchers( + new AntPathRequestMatcher(adminContextPath + "/login"), + new AntPathRequestMatcher(adminContextPath + "/assets/**"), + new AntPathRequestMatcher(adminContextPath + "/manage/**"), + new AntPathRequestMatcher(adminContextPath + "/actuator/**"), + new AntPathRequestMatcher(adminContextPath + "/login.html") + ).permitAll() + .anyRequest().authenticated() + ) + .formLogin(form -> form + .loginPage(adminContextPath + "/login") + .successHandler(successHandler)) + .logout(logout -> logout.logoutUrl(adminContextPath + "/logout")) + .httpBasic(Customizer.withDefaults()) + .csrf(csrf -> csrf.disable()); + return http.build(); + } } diff --git a/siam-monitor/src/main/resources/application-local.yml b/siam-monitor/src/main/resources/application-local.yml index afc2f79..1f82f89 100644 --- a/siam-monitor/src/main/resources/application-local.yml +++ b/siam-monitor/src/main/resources/application-local.yml @@ -7,6 +7,12 @@ spring: application: name: actuator-monitor + # Nacos注册中心 + cloud: + nacos: + discovery: + server-addr: 127.0.0.1:8848 + security: user: name: admin @@ -39,17 +45,7 @@ spring: socketFactory.class: javax.net.ssl.SSLSocketFactory socketFactory.port: 465 -#eureka配置 -eureka: - client: - service-url: - defaultZone: http://127.0.0.1:9000/eureka/ - register-with-eureka: true - fetch-registry: true - instance: - #配置使用ip地址来注册(默认是主机名称) - prefer-ip-address: true - #心跳检测暂时不配置 +# Nacos注册中心 # boot: # admin: diff --git a/siam-order/order-api/pom.xml b/siam-order/order-api/pom.xml index ef34d86..34b8b11 100644 --- a/siam-order/order-api/pom.xml +++ b/siam-order/order-api/pom.xml @@ -16,8 +16,6 @@ UTF-8 - 1.8 - 1.8 @@ -37,7 +35,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 exec diff --git a/siam-order/order-api/src/main/java/com/siam/package_order/entity/Order.java b/siam-order/order-api/src/main/java/com/siam/package_order/entity/Order.java index 669527c..4eab54f 100644 --- a/siam-order/order-api/src/main/java/com/siam/package_order/entity/Order.java +++ b/siam-order/order-api/src/main/java/com/siam/package_order/entity/Order.java @@ -5,8 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; @@ -14,7 +13,7 @@ import java.util.List; @Data -@ApiModel(value = "订单表") + @Schema(description= "订单表") @TableName("tb_order") public class Order { diff --git a/siam-order/order-api/src/main/java/com/siam/package_order/entity/OrderDetail.java b/siam-order/order-api/src/main/java/com/siam/package_order/entity/OrderDetail.java index c01b1ee..513a863 100644 --- a/siam-order/order-api/src/main/java/com/siam/package_order/entity/OrderDetail.java +++ b/siam-order/order-api/src/main/java/com/siam/package_order/entity/OrderDetail.java @@ -3,47 +3,46 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; import java.util.List; @Data -@ApiModel(value = "订单商品详情表") + @Schema(description= "订单商品详情表") @TableName("tb_order_detail") public class OrderDetail { - @ApiModelProperty(notes = "主键id") + @Schema(description = "主键id") @TableId(type = IdType.AUTO) private Integer id; @TableField(exist = false) List ids; - @ApiModelProperty(notes = "订单id") + @Schema(description = "订单id") private Integer orderId; - @ApiModelProperty(notes = "商品id") + @Schema(description = "商品id") private Integer goodsId; - @ApiModelProperty(notes = "商品名称") + @Schema(description = "商品名称") private String goodsName; - @ApiModelProperty(notes = "商品主图") + @Schema(description = "商品主图") private String mainImage; - @ApiModelProperty(notes = "商品规格 JSON格式") + @Schema(description = "商品规格 JSON格式") private String specList; - @ApiModelProperty(notes = "价格") + @Schema(description = "价格") private BigDecimal price; - @ApiModelProperty(notes = "购买数量") + @Schema(description = "购买数量") private Integer number; - @ApiModelProperty(notes = "小计") + @Schema(description = "小计") private BigDecimal subtotal; private BigDecimal packingCharges; diff --git a/siam-order/order-api/src/main/java/com/siam/package_order/model/dto/PlatformPayDto.java b/siam-order/order-api/src/main/java/com/siam/package_order/model/dto/PlatformPayDto.java index 9bff1ef..7177863 100644 --- a/siam-order/order-api/src/main/java/com/siam/package_order/model/dto/PlatformPayDto.java +++ b/siam-order/order-api/src/main/java/com/siam/package_order/model/dto/PlatformPayDto.java @@ -4,8 +4,8 @@ import org.hibernate.validator.constraints.Range; import org.springframework.web.bind.annotation.RequestParam; -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; import java.math.BigDecimal; /** diff --git a/siam-order/order-api/src/main/java/com/siam/package_order/model/param/OrderParam.java b/siam-order/order-api/src/main/java/com/siam/package_order/model/param/OrderParam.java index e289bfd..01d9038 100644 --- a/siam-order/order-api/src/main/java/com/siam/package_order/model/param/OrderParam.java +++ b/siam-order/order-api/src/main/java/com/siam/package_order/model/param/OrderParam.java @@ -4,18 +4,17 @@ import com.siam.package_common.model.valid_group.ValidGroupOfId; import com.siam.package_order.entity.Order; import com.siam.package_order.entity.OrderRefund; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import org.hibernate.validator.constraints.Range; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; import java.math.BigDecimal; import java.util.Date; import java.util.List; @Data -@ApiModel(value = "订单表") + @Schema(description= "订单表") public class OrderParam extends Order { private Date startTime; @@ -55,7 +54,7 @@ public class OrderParam extends Order { private Integer excludeOrderId; @NotNull(message = "主键id不能为空", groups = {ValidGroupOfId.class}) - @ApiModelProperty(notes = "主键id") + @Schema(description = "主键id") private Integer id; /** diff --git a/siam-order/order-api/src/main/java/com/siam/package_order/model/vo/OrderVo.java b/siam-order/order-api/src/main/java/com/siam/package_order/model/vo/OrderVo.java index bb4a36b..acc9aee 100644 --- a/siam-order/order-api/src/main/java/com/siam/package_order/model/vo/OrderVo.java +++ b/siam-order/order-api/src/main/java/com/siam/package_order/model/vo/OrderVo.java @@ -1,13 +1,13 @@ package com.siam.package_order.model.vo; import com.siam.package_order.entity.OrderDetail; -import io.swagger.annotations.ApiModel; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.List; @Data -@ApiModel(value = "订单表") + @Schema(description= "订单表") public class OrderVo { private Object order; diff --git a/siam-order/order-api/src/main/java/com/siam/package_order/model/vo/OrderVo2.java b/siam-order/order-api/src/main/java/com/siam/package_order/model/vo/OrderVo2.java index d18793f..4c84e7e 100644 --- a/siam-order/order-api/src/main/java/com/siam/package_order/model/vo/OrderVo2.java +++ b/siam-order/order-api/src/main/java/com/siam/package_order/model/vo/OrderVo2.java @@ -3,13 +3,13 @@ import com.siam.package_order.entity.OrderRefund; import com.siam.package_order.entity.OrderRefundGoods; import com.siam.package_order.entity.OrderRefundProcess; -import io.swagger.annotations.ApiModel; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.List; @Data -@ApiModel(value = "订单表") + @Schema(description= "订单表") public class OrderVo2 { private OrderRefund orderRefund; diff --git a/siam-order/order-provider/pom.xml b/siam-order/order-provider/pom.xml index 5270c1b..5f5e997 100644 --- a/siam-order/order-provider/pom.xml +++ b/siam-order/order-provider/pom.xml @@ -16,8 +16,6 @@ UTF-8 - 1.8 - 1.8 4.1.1 @@ -99,72 +97,40 @@ - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - 2.1.2.RELEASE - - - - - org.springframework.cloud - spring-cloud-starter-netflix-hystrix - 2.1.2.RELEASE - - - - - org.springframework.cloud - spring-cloud-starter-hystrix-dashboard - 1.2.3.RELEASE - - - + com.alibaba.cloud - spring-cloud-starter-alibaba-seata - 2021.1 - - - io.seata - seata-spring-boot-starter - - + spring-cloud-starter-alibaba-nacos-discovery + - io.seata - seata-spring-boot-starter - 1.3.0 + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config org.springframework.boot spring-boot-starter-actuator - 2.3.3.RELEASE io.micrometer micrometer-registry-prometheus - 1.5.4 - - - - - - - net.logstash.logback logstash-logback-encoder - 6.6 + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui @@ -174,7 +140,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 com.siam.package_order.OrderApplication diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/OrderApplication.java b/siam-order/order-provider/src/main/java/com/siam/package_order/OrderApplication.java index 1da786a..7e9e68a 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/OrderApplication.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/OrderApplication.java @@ -1,19 +1,19 @@ package com.siam.package_order; -import org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; -import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; +import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; -//@EnableHystrix -//@EnableHystrixDashboard -@EnableCircuitBreaker @EnableFeignClients("com.siam") -@EnableEurekaClient -@SpringBootApplication(scanBasePackages = "com.siam", exclude = {RocketMQAutoConfiguration.class}) +@EnableDiscoveryClient +@SpringBootApplication(scanBasePackages = "com.siam", exclude = { + MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class +}) @MapperScan(basePackages = {"com.siam.**.mapper"}) public class OrderApplication { diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/config/MybatisPlusConfig.java b/siam-order/order-provider/src/main/java/com/siam/package_order/config/MybatisPlusConfig.java index 9a5614d..91c2e6f 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/config/MybatisPlusConfig.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/config/MybatisPlusConfig.java @@ -1,6 +1,8 @@ package com.siam.package_order.config; -import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -19,8 +21,11 @@ public class MybatisPlusConfig { * 分页插件 */ @Bean - public PaginationInterceptor paginationInterceptor() { - return new PaginationInterceptor(); + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); + interceptor.addInnerInterceptor(paginationInnerInterceptor); + return interceptor; } } \ No newline at end of file diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/config/SeataConfig.java b/siam-order/order-provider/src/main/java/com/siam/package_order/config/SeataConfig.java index 215c402..5efe888 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/config/SeataConfig.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/config/SeataConfig.java @@ -1,6 +1,8 @@ //package com.siam.package_order.config; // -//import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +//import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; //import com.siam.package_common.util.StringUtils; //import com.zaxxer.hikari.HikariDataSource; //import io.seata.rm.datasource.DataSourceProxy; diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/config/Swagger2Config.java b/siam-order/order-provider/src/main/java/com/siam/package_order/config/Swagger2Config.java deleted file mode 100644 index 33e60c5..0000000 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/config/Swagger2Config.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.siam.package_order.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; - -@Configuration -@EnableSwagger2 -public class Swagger2Config { - - @Bean - public Docket createRestApi() { - return new Docket(DocumentationType.SWAGGER_2) - .apiInfo(apiInfo()) - .select() - .apis(RequestHandlerSelectors.basePackage("com.siam"))//扫描包路径 - .paths(PathSelectors.any()) - .build(); - } - - // 构建api文档的详细信息函数,注意这里的注解引用的是哪个 - private ApiInfo apiInfo() { - return new ApiInfoBuilder() - .title("暹罗外卖-订单服务接口文档")//页面标题 - .description("")//描述 - .version("1.0")//版本号 - .build(); - } -} \ No newline at end of file diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/admin/AdminOrderController.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/admin/AdminOrderController.java index 46785a7..0e6cd4f 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/admin/AdminOrderController.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/admin/AdminOrderController.java @@ -9,33 +9,34 @@ import com.siam.package_order.model.param.OrderParam; import com.siam.package_order.service.OrderService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import java.text.ParseException; import java.util.*; @RestController @RequestMapping(value = "/rest/admin/order") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台订单模块相关接口", description = "AdminOrderController") +@Tag(name = "后台订单模块相关接口", description = "AdminOrderController") public class AdminOrderController { @Resource(name = "orderServiceImpl") private OrderService orderService; - @ApiOperation(value = "订单列表") + @Operation(summary = "订单列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) OrderParam param){ Page page = orderService.getListByPageWithAsc(param); return BasicResult.success(page); } - @ApiOperation("打印小票") + @Operation(summary = "打印小票") public BasicResult printRceceipts(@RequestBody @Validated(value = {}) OrderParam param){ for(String id : param.getIds()){ orderService.printRceceipts(Integer.valueOf(id)); @@ -43,7 +44,7 @@ public BasicResult printRceceipts(@RequestBody @Validated(value = {}) OrderParam return BasicResult.success(); } - @ApiOperation(value = "查询单个订单信息") + @Operation(summary = "查询单个订单信息") @PostMapping(value = "/selectById") public BasicResult selectById(@RequestBody @Validated(value = {}) OrderParam param){ Order dbOrder = orderService.selectByPrimaryKey(param.getId()); @@ -53,42 +54,42 @@ public BasicResult selectById(@RequestBody @Validated(value = {}) OrderParam par return BasicResult.success(dbOrder); } - @ApiOperation(value = "批量修改订单的是否已打印状态为已打印") + @Operation(summary = "批量修改订单的是否已打印状态为已打印") @PostMapping(value = "/batchUpdateIsPrintedTrue") public BasicResult batchUpdateIsPrintedTrue(@RequestBody @Validated(value = {}) OrderParam param){ orderService.batchUpdateIsPrintedTrue(param); return BasicResult.success(); } - @ApiOperation(value = "今日订单列表") + @Operation(summary = "今日订单列表") @PostMapping(value = "/todayOrderList") public BasicResult todayOrderList(@RequestBody @Validated(value = {}) OrderParam param){ Page page = orderService.getListByTodayOrderWithAsc(param); return BasicResult.success(page); } - @ApiOperation(value = "查询所有订单标签页的待处理数量") + @Operation(summary = "查询所有订单标签页的待处理数量") @PostMapping(value = "/selectAllTabWaitHandleNum") public BasicResult selectAllTabWaitHandleNum(@RequestBody @Validated(value = {}) OrderParam param){ Map map = this.orderService.selectAllTabWaitHandleNum(param); return BasicResult.success(map); } - @ApiOperation(value = "查询所有已付款未打印的订单") + @Operation(summary = "查询所有已付款未打印的订单") @PostMapping(value = "/waitPrintOrderList") public BasicResult waitPrintOrderList(@RequestBody @Validated(value = {}) OrderParam param){ List orders = orderService.waitPrintOrderList(param); return BasicResult.success(orders); } - @ApiOperation(value = "订单统计(支付成功订单数量、取消订单数量、退款订单数量,按自取或者外卖分开)") + @Operation(summary = "订单统计(支付成功订单数量、取消订单数量、退款订单数量,按自取或者外卖分开)") @PostMapping(value = "/countOrder") public BasicResult countOrder(@RequestBody @Validated(value = {}) OrderParam param){ Map count=orderService.countOrder(param); return BasicResult.success(count); } - @ApiOperation(value = "售后处理订单列表") + @Operation(summary = "售后处理订单列表") @PostMapping(value = "/afterSalesList") public BasicResult afterSalesList(@RequestBody @Validated(value = {}) OrderParam param){ Page page = orderService.getAfterSalesListByPageWithAsc(param); diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/admin/AdminOrderDetailController.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/admin/AdminOrderDetailController.java index cecae29..86159de 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/admin/AdminOrderDetailController.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/admin/AdminOrderDetailController.java @@ -6,10 +6,16 @@ import com.siam.package_common.constant.BasicResultCode; import com.siam.package_order.entity.OrderDetail; import com.siam.package_order.service.OrderDetailService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -18,28 +24,12 @@ @RestController @RequestMapping(value = "/rest/admin/orderDetail") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台订单商品详情模块相关接口", description = "AdminOrderDetailController") +@Tag(name = "后台订单商品详情模块相关接口", description = "AdminOrderDetailController") public class AdminOrderDetailController { @Autowired private OrderDetailService orderDetailService; - @ApiOperation(value = "订单商品详情列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "订单商品详情表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "orderId", value = "订单id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "goodsId", value = "商品id", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsName", value = "商品名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specList", value = "商品规格 JSON格式", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsSpecs", value = "规格组合 JSON格式", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "价格", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "number", value = "购买数量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "subtotal", value = "小计", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "remark", value = "备注", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) - @PostMapping(value = "/list") + @Operation(summary = "订单商品详情列表")@PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) OrderDetail orderDetail){ BasicData basicResult = new BasicData(); @@ -49,20 +39,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) OrderDetail orderDet } - @ApiOperation(value = "新增订单商品详情") - @ApiImplicitParams({ - @ApiImplicitParam(name = "orderId", value = "订单id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "goodsId", value = "商品id", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsName", value = "商品名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specList", value = "商品规格 JSON格式", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsSpecs", value = "规格组合 JSON格式", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "价格", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "number", value = "购买数量", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "subtotal", value = "小计", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "remark", value = "备注", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - }) - @PostMapping(value = "/insert") + @Operation(summary = "新增订单商品详情")@PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) OrderDetail orderDetail){ BasicResult basicResult = new BasicResult(); @@ -74,21 +51,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) OrderDetail orderD return basicResult; } - @ApiOperation(value = "修改订单商品详情") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "订单商品详情表主键id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "orderId", value = "订单id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "goodsId", value = "商品id", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsName", value = "商品名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specList", value = "商品规格 JSON格式", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsSpecs", value = "规格组合 JSON格式", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "价格", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "number", value = "购买数量", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "subtotal", value = "小计", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "remark", value = "备注", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - }) - @PostMapping(value = "/update") + @Operation(summary = "修改订单商品详情")@PostMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) OrderDetail orderDetail){ BasicResult basicResult = new BasicResult(); @@ -100,11 +63,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) OrderDetail orderD return basicResult; } - @ApiOperation(value = "删除订单商品详情(含批量操作)") - @ApiImplicitParams({ - @ApiImplicitParam(name = "ids", value = "订单商品详情表主键id(批量删除时id以逗号分隔)", required = true, paramType = "query", dataType = "string"), - }) - @PostMapping(value = "/delete") + @Operation(summary = "删除订单商品详情(含批量操作)")@PostMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) OrderDetail param){ BasicResult basicResult = new BasicResult(); diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/AppraiseController.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/AppraiseController.java index 3a8ad82..7596282 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/AppraiseController.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/AppraiseController.java @@ -24,8 +24,8 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.Date; import java.util.Map; diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/CommonController.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/CommonController.java index 1e16f8d..da2e2e4 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/CommonController.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/CommonController.java @@ -7,10 +7,11 @@ import com.siam.package_order.service.CommonService; import com.siam.package_user.entity.DeliveryAddress; import com.siam.package_user.feign.DeliveryAddressFeignApi; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -26,7 +27,7 @@ @RestController @RequestMapping(value = "/rest/common") @Transactional(rollbackFor = Exception.class) -@Api(tags = "通用模块相关接口", description = "CommonController") +@Tag(name = "通用模块相关接口", description = "CommonController") public class CommonController { @Autowired @@ -41,10 +42,7 @@ public class CommonController { // @Autowired // private ShopFeignClient shopFeignApi; - @ApiOperation(value = "查询订单配送费") - @ApiImplicitParams({ - @ApiImplicitParam(name = "deliveryAddressId", value = "收货地址id", required = false, paramType = "query", dataType = "int") - }) + @Operation(summary = "查询订单配送费") @PostMapping(value = "/selectDeliveryFee") public BasicResult selectDeliveryFee(@RequestBody @Validated(value = {}) CommonParam param) { BasicData basicResult = new BasicData(); @@ -61,11 +59,7 @@ public BasicResult selectDeliveryFee(@RequestBody @Validated(value = {}) CommonP return BasicResult.success(deliveryFee); } - /*@ApiOperation(value = "查询是否有门店可以配送") - @ApiImplicitParams({ - @ApiImplicitParam(name = "deliveryAddressId", value = "收货地址id", required = false, paramType = "query", dataType = "int") - }) - @PostMapping(value = "/selectHasShopDelivery") + /*@Operation(summary = "查询是否有门店可以配送")@PostMapping(value = "/selectHasShopDelivery") public BasicResult selectHasShopDelivery(@RequestParam(required = false) Integer deliveryAddressId){ BasicData basicResult = new BasicData(); @@ -119,7 +113,7 @@ public BasicResult selectHasShopDelivery(@RequestParam(required = false) Integer // @Autowired // private WebSocket webSocket; // -// @ApiOperation(value = "websocket推送消息给前端") +// @Operation(summary = "websocket推送消息给前端") // @GetMapping(value = "/websocketPush") // public BasicResult websocketPush(String name, String mark){ // BasicResult basicResult = new BasicResult(); diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/GiveLikeController.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/GiveLikeController.java index 17cc4a0..5d1b55a 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/GiveLikeController.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/GiveLikeController.java @@ -14,7 +14,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.Date; /** diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/MerchantOrderController.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/MerchantOrderController.java index eebb542..f123b36 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/MerchantOrderController.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/MerchantOrderController.java @@ -35,10 +35,10 @@ import com.siam.package_user.util.TokenUtil; import com.siam.package_weixin_basic.service.WxNotifyService; import com.siam.package_weixin_basic.service.WxPublicPlatformNotifyService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -47,8 +47,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.text.ParseException; import java.util.*; @@ -58,7 +58,7 @@ @RestController @RequestMapping(value = "/rest/merchant/order") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端订单模块相关接口", description = "MerchantOrderController") +@Tag(name = "商家端订单模块相关接口", description = "MerchantOrderController") public class MerchantOrderController { @Resource(name = "orderServiceImpl") @@ -102,38 +102,7 @@ public class MerchantOrderController { private Lock lock = new ReentrantLock(); - @ApiOperation(value = "订单列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "订单表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "memberId", value = "用户id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "orderNo", value = "订单编号,供客户查询", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsTotalQuantity", value = "商品总数量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "goodsTotalPrice", value = "商品总金额", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "packingCharges", value = "包装费", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "deliveryFee", value = "配送费", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "actualPrice", value = "实付款", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "shoppingWay", value = "购物方式 1=自取 2=配送", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "deliveryAddressId", value = "收货地址id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "contactRealname", value = "联系人姓名", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "contactPhone", value = "联系电话", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "contactProvince", value = "省份", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "contactCity", value = "城市", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "contactArea", value = "区/县", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "contactStreet", value = "详细地址(具体到街道门牌号)", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "contactSex", value = "联系人性别 0=无 1=先生 2=女士", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "remark", value = "备注", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "description", value = "订单描述", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "status", value = "订单状态 -1=售后处理状态 1=未付款 2=待处理 3=待自取(已处理) 4=待配送(已处理) 5=已配送 6=已完成 7=售后处理中 8=已退款 9=售后处理完成 10=已取消", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "tradeId", value = "用户交易id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "orderLogisticsId", value = "物流id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isInvoice", value = "是否开票", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "invoiceId", value = "发票id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDeleted", value = "是否删除 0=正常 1=已删除", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "shopId", value = "接单门店id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "shopName", value = "接单门店名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) + @Operation(summary = "订单列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) OrderParam param, HttpServletRequest request){ BasicData basicResult = new BasicData(); @@ -148,7 +117,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) OrderParam param, Ht } - @ApiOperation(value = "修改订单状态") + @Operation(summary = "修改订单状态") @PostMapping(value = "/updateStatus") public BasicResult updateStatus(@RequestBody @Validated(value = {}) OrderParam param){ BasicResult basicResult = new BasicResult(); @@ -266,10 +235,7 @@ public BasicResult updateStatus(@RequestBody @Validated(value = {}) OrderParam p return basicResult; } - @ApiOperation(value = "查询单个订单信息") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "订单表主键id", required = true, paramType = "query", dataType = "int"), - }) + @Operation(summary = "查询单个订单信息") @PostMapping(value = "/selectById") public BasicResult selectById(@RequestBody @Validated(value = {}) OrderParam param){ BasicData basicResult = new BasicData(); @@ -290,10 +256,7 @@ public BasicResult selectById(@RequestBody @Validated(value = {}) OrderParam par return BasicResult.success(dbOrder); } - @ApiOperation(value = "批量修改订单的是否已打印状态为已打印") - @ApiImplicitParams({ - @ApiImplicitParam(name = "idListStr", value = "订单表主键id", required = true, paramType = "query", dataType = "string"), - }) + @Operation(summary = "批量修改订单的是否已打印状态为已打印") @PostMapping(value = "/batchUpdateIsPrintedTrue") public BasicResult batchUpdateIsPrintedTrue(@RequestBody @Validated(value = {}) OrderParam param){ BasicResult basicResult = new BasicResult(); @@ -316,40 +279,7 @@ public BasicResult batchUpdateIsPrintedTrue(@RequestBody @Validated(value = {}) return basicResult; } - @ApiOperation(value = "今日订单列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "订单表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "memberId", value = "用户id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "orderNo", value = "订单编号,供客户查询", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsTotalQuantity", value = "商品总数量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "goodsTotalPrice", value = "商品总金额", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "packingCharges", value = "包装费", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "deliveryFee", value = "配送费", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "actualPrice", value = "实付款", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "shoppingWay", value = "购物方式 1=自取 2=配送", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "deliveryAddressId", value = "收货地址id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "contactRealname", value = "联系人姓名", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "contactPhone", value = "联系电话", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "contactProvince", value = "省份", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "contactCity", value = "城市", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "contactArea", value = "区/县", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "contactStreet", value = "详细地址(具体到街道门牌号)", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "contactSex", value = "联系人性别 0=无 1=先生 2=女士", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "remark", value = "备注", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "description", value = "订单描述", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "status", value = "订单状态 -1=售后处理状态 1=未付款 2=待处理 3=待自取(已处理) 4=待配送(已处理) 5=已配送 6=已完成 7=售后处理中 8=已退款 9=售后处理完成 10=已取消", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "tradeId", value = "用户交易id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "orderLogisticsId", value = "物流id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isInvoice", value = "是否开票", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "invoiceId", value = "发票id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDeleted", value = "是否删除 0=正常 1=已删除", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "shopId", value = "接单门店id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "shopName", value = "接单门店名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "startCreateTime", value = "下单开始时间", required = false, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "endCreateTime", value = "下单结束时间", required = false, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) + @Operation(summary = "今日订单列表") @PostMapping(value = "/todayOrderList") public BasicResult todayOrderList(@RequestBody @Validated(value = {}) OrderParam param, HttpServletRequest request){ BasicData basicResult = new BasicData(); @@ -363,7 +293,7 @@ public BasicResult todayOrderList(@RequestBody @Validated(value = {}) OrderParam return BasicResult.success(page); } - @ApiOperation(value = "查询所有订单标签页的待处理数量") + @Operation(summary = "查询所有订单标签页的待处理数量") @PostMapping(value = "/selectAllTabWaitHandleNum") public BasicResult selectAllTabWaitHandleNum(@RequestBody @Validated(value = {}) OrderParam param){ BasicData basicResult = new BasicData(); @@ -377,7 +307,7 @@ public BasicResult selectAllTabWaitHandleNum(@RequestBody @Validated(value = {}) orderLambdaQueryWrapper.eq(Order::getShopId, loginMerchant.getShopId()); orderLambdaQueryWrapper.eq(Order::getShoppingWay, Quantity.INT_1); orderLambdaQueryWrapper.eq(Order::getStatus, Quantity.INT_2); - int waitHandleNum = orderService.count(orderLambdaQueryWrapper); + long waitHandleNum = orderService.count(orderLambdaQueryWrapper); dataMap.put("waitHandleNum", waitHandleNum); //自取订单-待自取订单 @@ -385,7 +315,7 @@ public BasicResult selectAllTabWaitHandleNum(@RequestBody @Validated(value = {}) orderLambdaQueryWrapper.eq(Order::getShopId, loginMerchant.getShopId()); orderLambdaQueryWrapper.eq(Order::getShoppingWay, Quantity.INT_1); orderLambdaQueryWrapper.eq(Order::getStatus, Quantity.INT_3); - int waitPickUpNum = orderService.count(orderLambdaQueryWrapper); + long waitPickUpNum = orderService.count(orderLambdaQueryWrapper); dataMap.put("waitPickUpNum", waitPickUpNum); //外卖订单-待配送订单 @@ -393,7 +323,7 @@ public BasicResult selectAllTabWaitHandleNum(@RequestBody @Validated(value = {}) orderLambdaQueryWrapper.eq(Order::getShopId, loginMerchant.getShopId()); orderLambdaQueryWrapper.eq(Order::getShoppingWay, Quantity.INT_2); orderLambdaQueryWrapper.eq(Order::getStatus, Quantity.INT_4); - int waitDeliveryNum = orderService.count(orderLambdaQueryWrapper); + int waitDeliveryNum = (int) orderService.count(orderLambdaQueryWrapper); dataMap.put("waitDeliveryNum", waitDeliveryNum); //外卖订单-已配送订单 @@ -401,13 +331,13 @@ public BasicResult selectAllTabWaitHandleNum(@RequestBody @Validated(value = {}) orderLambdaQueryWrapper.eq(Order::getShopId, loginMerchant.getShopId()); orderLambdaQueryWrapper.eq(Order::getShoppingWay, Quantity.INT_2); orderLambdaQueryWrapper.eq(Order::getStatus, Quantity.INT_5); - int deliveredNum = orderService.count(orderLambdaQueryWrapper); + int deliveredNum = (int) orderService.count(orderLambdaQueryWrapper); dataMap.put("deliveredNum", deliveredNum); return BasicResult.success(dataMap); } - @ApiOperation(value = "查询所有已付款未打印的订单") + @Operation(summary = "查询所有已付款未打印的订单") @PostMapping(value = "/waitPrintOrderList") public BasicResult waitPrintOrderList(@RequestBody @Validated(value = {}) OrderParam param){ BasicData basicResult = new BasicData(); @@ -455,11 +385,7 @@ public BasicResult waitPrintOrderList(@RequestBody @Validated(value = {}) OrderP return BasicResult.success(orders); } - @ApiOperation(value = "订单统计(支付成功订单数量、取消订单数量、退款订单数量,按自取或者外卖分开)") - @ApiImplicitParams({ - @ApiImplicitParam(name = "startCreateTime", value = "下单开始时间", required = false, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "endCreateTime", value = "下单结束时间", required = false, paramType = "query", dataType = "Date"), - }) + @Operation(summary = "订单统计(支付成功订单数量、取消订单数量、退款订单数量,按自取或者外卖分开)") @PostMapping(value = "/countOrder") public BasicResult countOrder(@RequestBody @Validated(value = {}) OrderParam order, HttpServletRequest request){ BasicData basicResult = new BasicData(); @@ -473,7 +399,7 @@ public BasicResult countOrder(@RequestBody @Validated(value = {}) OrderParam ord return BasicResult.success(count); } - @ApiOperation(value = "售后处理订单列表") + @Operation(summary = "售后处理订单列表") @PostMapping(value = "/afterSalesList") public BasicResult afterSalesList(@RequestBody @Validated(value = {}) OrderParam param, HttpServletRequest request){ BasicData basicResult = new BasicData(); diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/MerchantOrderDetailController.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/MerchantOrderDetailController.java index d360cdf..cf5c2cf 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/MerchantOrderDetailController.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/MerchantOrderDetailController.java @@ -5,10 +5,16 @@ import com.siam.package_common.entity.BasicResult; import com.siam.package_order.entity.OrderDetail; import com.siam.package_order.service.OrderDetailService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -17,28 +23,12 @@ @RestController @RequestMapping(value = "/rest/merchant/orderDetail") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端订单商品详情模块相关接口", description = "MerchantOrderDetailController") +@Tag(name = "商家端订单商品详情模块相关接口", description = "MerchantOrderDetailController") public class MerchantOrderDetailController { @Autowired private OrderDetailService orderDetailService; - @ApiOperation(value = "订单商品详情列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "订单商品详情表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "orderId", value = "订单id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "goodsId", value = "商品id", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsName", value = "商品名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specList", value = "商品规格 JSON格式", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsSpecs", value = "规格组合 JSON格式", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "价格", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "number", value = "购买数量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "subtotal", value = "小计", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "remark", value = "备注", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) - @PostMapping(value = "/list") + @Operation(summary = "订单商品详情列表")@PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) OrderDetail orderDetail){ BasicData basicResult = new BasicData(); @@ -48,20 +38,8 @@ public BasicResult list(@RequestBody @Validated(value = {}) OrderDetail orderDet } -// @ApiOperation(value = "新增订单商品详情") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "orderId", value = "订单id", required = true, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "goodsId", value = "商品id", required = true, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "goodsName", value = "商品名称", required = true, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "specList", value = "商品规格 JSON格式", required = true, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "goodsSpecs", value = "规格组合 JSON格式", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "price", value = "价格", required = true, paramType = "query", dataType = "BigDecimal"), -// @ApiImplicitParam(name = "number", value = "购买数量", required = true, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "subtotal", value = "小计", required = true, paramType = "query", dataType = "BigDecimal"), -// @ApiImplicitParam(name = "remark", value = "备注", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), -// }) -// @PostMapping(value = "/insert") +// @Operation(summary = "新增订单商品详情") +//// @PostMapping(value = "/insert") // public BasicResult insert(OrderDetail orderDetail){ // BasicResult basicResult = new BasicResult(); // @@ -73,21 +51,8 @@ public BasicResult list(@RequestBody @Validated(value = {}) OrderDetail orderDet // return basicResult; // } // -// @ApiOperation(value = "修改订单商品详情") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "id", value = "订单商品详情表主键id", required = true, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "orderId", value = "订单id", required = true, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "goodsId", value = "商品id", required = true, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "goodsName", value = "商品名称", required = true, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "specList", value = "商品规格 JSON格式", required = true, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "goodsSpecs", value = "规格组合 JSON格式", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "price", value = "价格", required = true, paramType = "query", dataType = "BigDecimal"), -// @ApiImplicitParam(name = "number", value = "购买数量", required = true, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "subtotal", value = "小计", required = true, paramType = "query", dataType = "BigDecimal"), -// @ApiImplicitParam(name = "remark", value = "备注", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), -// }) -// @PostMapping(value = "/update") +// @Operation(summary = "修改订单商品详情") +//// @PostMapping(value = "/update") // public BasicResult update(OrderDetail orderDetail){ // BasicResult basicResult = new BasicResult(); // @@ -99,11 +64,8 @@ public BasicResult list(@RequestBody @Validated(value = {}) OrderDetail orderDet // return basicResult; // } // -// @ApiOperation(value = "删除订单商品详情(含批量操作)") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "ids", value = "订单商品详情表主键id(批量删除时id以逗号分隔)", required = true, paramType = "query", dataType = "string"), -// }) -// @PostMapping(value = "/delete") +// @Operation(summary = "删除订单商品详情(含批量操作)") +//// @PostMapping(value = "/delete") // public BasicResult delete(@RequestParam(value = "ids", required = true) List ids){ // BasicResult basicResult = new BasicResult(); // diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/OrderController.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/OrderController.java index d3ec63e..ca7b665 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/OrderController.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/OrderController.java @@ -2,31 +2,39 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.siam.package_common.entity.BasicResult; +import com.siam.package_common.exception.StoneCustomerException; import com.siam.package_order.entity.Order; import com.siam.package_order.model.param.OrderParam; import com.siam.package_order.model.vo.OrderVo; import com.siam.package_order.model.vo.OrderVo2; import com.siam.package_order.service.*; import com.siam.package_order.service.OrderService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import com.siam.package_user.auth.cache.MemberSessionManager; +import com.siam.package_user.entity.Member; +import com.siam.package_user.util.TokenUtil; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.client.exception.MQBrokerException; import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.remoting.exception.RemotingException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import java.io.IOException; import java.util.*; +import java.util.concurrent.TimeUnit; @Slf4j @RestController @RequestMapping(value = "/rest/member/order") @Transactional(rollbackFor = Exception.class) -@Api(tags = "订单模块相关接口", description = "OrderController") +@Tag(name = "订单模块相关接口", description = "OrderController") public class OrderController { @Resource(name = "orderServiceImpl") @@ -35,6 +43,12 @@ public class OrderController { @Resource(name = "rewardServiceImpl") private RewardService rewardService; + @Autowired + private StringRedisTemplate stringRedisTemplate; + + @Autowired + private MemberSessionManager memberSessionManager; + /** * 订单列表 * @@ -67,8 +81,19 @@ public BasicResult selectById(@RequestBody @Validated(value = {}) OrderParam par */ @PostMapping(value = "/insert") public BasicResult insertOrder(@RequestBody @Validated(value = {}) OrderParam param) throws InterruptedException, RemotingException, MQClientException, MQBrokerException { - Order order = orderService.insert(param); - return BasicResult.success(order); + // Redis 分布式锁 - 防重复下单 + Member loginMember = memberSessionManager.getSession(TokenUtil.getToken()); + String lockKey = "order:create:lock:" + loginMember.getId(); + Boolean isLocked = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "1", 5, TimeUnit.SECONDS); + if (Boolean.FALSE.equals(isLocked)) { + throw new StoneCustomerException("正在处理中,请勿重复点击"); + } + try { + Order order = orderService.insert(param); + return BasicResult.success(order); + } finally { + // 订单创建是长流程(含分布式事务),此处不主动删锁,依赖 5 秒过期防止并发 + } } /** @@ -112,14 +137,14 @@ public BasicResult applyRefund(@RequestBody @Validated(value = {}) OrderParam pa * @param param * @return */ - @ApiOperation(value = "修改订单状态为已确认收货") + @Operation(summary = "修改订单状态为已确认收货") @PostMapping(value = "/confirmReceipt") public BasicResult confirmReceipt(@RequestBody @Validated(value = {}) OrderParam param){ orderService.confirmReceipt(param); return BasicResult.success(); } - @ApiOperation(value = "删除订单") + @Operation(summary = "删除订单") @PostMapping(value = "/delete") public BasicResult deleteOrder(@RequestBody @Validated(value = {}) OrderParam param){ diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/OrderDetailController.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/OrderDetailController.java index f476f27..b9a6271 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/OrderDetailController.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/OrderDetailController.java @@ -1,7 +1,11 @@ package com.siam.package_order.controller.member; import com.siam.package_order.service.OrderDetailService; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RequestMapping; @@ -10,28 +14,12 @@ @RestController @RequestMapping(value = "/rest/orderDetail") @Transactional(rollbackFor = Exception.class) -@Api(tags = "订单商品详情模块相关接口", description = "OrderDetailController") +@Tag(name = "订单商品详情模块相关接口", description = "OrderDetailController") public class OrderDetailController { @Autowired private OrderDetailService orderDetailService; - /*@ApiOperation(value = "订单商品详情列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "订单商品详情表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "orderId", value = "订单id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "goodsId", value = "商品id", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsName", value = "商品名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "specList", value = "商品规格 JSON格式", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsSpecs", value = "规格组合 JSON格式", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "price", value = "价格", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "number", value = "购买数量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "subtotal", value = "小计", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "remark", value = "备注", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) - @PostMapping(value = "/list") + /*@Operation(summary = "订单商品详情列表")@PostMapping(value = "/list") public BasicResult list(int pageNo, int pageSize, OrderDetail orderDetail){ BasicData basicResult = new BasicData(); diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/PayDemoController.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/PayDemoController.java index 6e6004c..ebda1de 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/PayDemoController.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/PayDemoController.java @@ -37,10 +37,16 @@ import com.siam.package_util.feign.SettingFeignApi; import com.siam.package_weixin_pay.config.WxpayConfigDemo; import com.siam.package_weixin_pay.entity.WxpayBean; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,9 +61,9 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.BufferedOutputStream; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; @@ -67,7 +73,7 @@ @RestController @RequestMapping(value = "/rest/payDemo") @Transactional(rollbackFor = Exception.class) -@Api(tags = "支付模块相关接口", description = "PayController") +@Tag(name = "支付模块相关接口", description = "PayController") public class PayDemoController { private Logger logger = LoggerFactory.getLogger(PayDemoController.class); @@ -111,14 +117,7 @@ public class PayDemoController { @Autowired private MemberFeignApi memberFeignApi; - @ApiOperation(value = "支付宝支付") - @ApiImplicitParams({ - @ApiImplicitParam(name = "out_trade_no", value = "商户订单号", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "subject", value = "订单名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "total_amount", value = "付款金额", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "body", value = "商品描述", required = false, paramType = "query", dataType = "string"), - }) - @PostMapping(value = "/alipay") + @Operation(summary = "支付宝支付")@PostMapping(value = "/alipay") public BasicResult alipay(AlipayBean alipayBean){ BasicData basicResult = new BasicData(); try { @@ -148,7 +147,7 @@ public BasicResult alipay(AlipayBean alipayBean){ return basicResult; } - @ApiOperation(value = "支付宝支付回调") + @Operation(summary = "支付宝支付回调") @PostMapping(value = "/alipayCallback") public BasicResult alipayCallback(HttpServletRequest request) throws UnsupportedEncodingException, AlipayApiException { BasicResult basicResult = new BasicResult(); @@ -261,14 +260,7 @@ public BasicResult alipayCallback(HttpServletRequest request) throws Unsupported } - @ApiOperation(value = "微信支付") - @ApiImplicitParams({ - @ApiImplicitParam(name = "out_trade_no", value = "商户订单号", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "subject", value = "订单名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "total_amount", value = "付款金额", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "body", value = "商品描述", required = false, paramType = "query", dataType = "string"), - }) - @PostMapping(value = "/wxpay") + @Operation(summary = "微信支付")@PostMapping(value = "/wxpay") public BasicResult wxpay(WxpayBean wxpayBean, HttpServletRequest request, WxPayUnifiedOrderRequest wxreq){ BasicData basicResult = new BasicData(); try { @@ -320,7 +312,7 @@ public BasicResult wxpay(WxpayBean wxpayBean, HttpServletRequest request, WxPayU } - @ApiOperation(value = "微信支付回调") + @Operation(summary = "微信支付回调") @PostMapping(value = "/wxpayCallback") public BasicResult wxpayCallback(String xmlData,HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException, AlipayApiException, WxPayException { BasicResult basicResult = new BasicResult(); @@ -361,14 +353,7 @@ public String setXML(String return_code, String return_msg) { return ""; } - @ApiOperation(value = "微信支付_2") - @ApiImplicitParams({ - @ApiImplicitParam(name = "out_trade_no", value = "商户订单号", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "subject", value = "订单名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "total_amount", value = "付款金额", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "body", value = "商品描述", required = false, paramType = "query", dataType = "string"), - }) - @PostMapping(value = "/wxpay_2") + @Operation(summary = "微信支付_2")@PostMapping(value = "/wxpay_2") public BasicResult wxpay_2(WxpayBean wxpayBean, HttpServletRequest request, WxPayUnifiedOrderRequest wxreq){ BasicData basicResult = new BasicData(); basicResult.setData("http://www.baidu.com"); @@ -378,14 +363,7 @@ public BasicResult wxpay_2(WxpayBean wxpayBean, HttpServletRequest request, WxPa return basicResult; } - @ApiOperation(value = "订单支付(过渡接口)") - @ApiImplicitParams({ - @ApiImplicitParam(name = "out_trade_no", value = "商户订单号", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "subject", value = "订单名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "total_amount", value = "付款金额", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "body", value = "商品描述", required = false, paramType = "query", dataType = "string"), - }) - @PostMapping(value = "/orderPay") + @Operation(summary = "订单支付(过渡接口)")@PostMapping(value = "/orderPay") public BasicResult orderPay(WxpayBean wxpayBean, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/PlatformPayController.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/PlatformPayController.java index 6c77085..18f6ca8 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/PlatformPayController.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/PlatformPayController.java @@ -26,8 +26,9 @@ import com.siam.package_user.util.TokenUtil; import com.siam.package_weixin_basic.util.WxdecodeUtils; import com.siam.package_weixin_pay.config.WxPayConfig; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.client.exception.MQBrokerException; import org.apache.rocketmq.client.exception.MQClientException; @@ -40,8 +41,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; import java.io.IOException; import java.math.BigDecimal; import java.util.Date; @@ -50,7 +51,7 @@ @RestController @RequestMapping(value = "/rest/member/platformPay") @Transactional(rollbackFor = Exception.class) -@Api(tags = "平台支付模块相关接口", description = "PlatformPayController") +@Tag(name = "平台支付模块相关接口", description = "PlatformPayController") public class PlatformPayController { @Autowired @@ -93,7 +94,7 @@ public class PlatformPayController { * @return * @author 暹罗 */ - @ApiOperation(value = "使用平台余额支付") + @Operation(summary = "使用平台余额支付") @PostMapping(value = "/byBalance") public BasicResult byBalance(@RequestBody @Validated PlatformPayDto platformPayDto, HttpServletRequest request) throws InterruptedException, RemotingException, MQClientException, MQBrokerException, IOException { //TODO-PS:但是如果按照微信支付的步骤来,只要某个步骤失败,事务就会回滚--莫非这种就是不能在Controller上添加事务注解的原因? diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/ReplyController.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/ReplyController.java index 8b21301..7c6f059 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/ReplyController.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/ReplyController.java @@ -15,7 +15,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.Map; /** diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/WxPayService.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/WxPayService.java index 733708a..ce6a034 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/WxPayService.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/WxPayService.java @@ -31,7 +31,7 @@ import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Service; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import javax.net.ssl.SSLContext; import java.io.IOException; import java.io.InputStream; diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/internal/WxNotifyTemplateController.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/internal/WxNotifyTemplateController.java index 74e0aec..6210bd0 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/internal/WxNotifyTemplateController.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/internal/WxNotifyTemplateController.java @@ -4,7 +4,8 @@ import com.siam.package_common.entity.BasicResult; import com.siam.package_common.constant.BasicResultCode; import com.siam.package_order.service.OrderService; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -12,14 +13,14 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import java.util.*; @Slf4j @RestController @RequestMapping(value = "/rest/wxNotifyTemplate") @Transactional(rollbackFor = Exception.class) -@Api(tags = "微信服务通知模板模块相关接口", description = "WxNotifyTemplateController") +@Tag(name = "微信服务通知模板模块相关接口", description = "WxNotifyTemplateController") public class WxNotifyTemplateController { @Resource(name = "orderServiceImpl") diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/internal/WxPayController.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/internal/WxPayController.java index 5f9bba9..305b501 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/internal/WxPayController.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/internal/WxPayController.java @@ -30,8 +30,9 @@ import com.siam.package_weixin_pay.config.WxPayConfig; import com.siam.package_weixin_pay.entity.WxPayDto; import com.siam.package_weixin_pay.util.PayUtil; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -41,10 +42,10 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.annotation.Resource; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.InputStreamReader; @@ -52,12 +53,15 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.springframework.data.redis.core.StringRedisTemplate; @Slf4j @RestController @RequestMapping(value = "/rest/member/wxPay") @Transactional(rollbackFor = Exception.class) -@Api(tags = "微信支付模块相关接口", description = "WxPayController") +@Tag(name = "微信支付模块相关接口", description = "WxPayController") public class WxPayController { @Autowired @@ -96,12 +100,15 @@ public class WxPayController { @Autowired private RedisUtils redisUtils; + @Autowired + private StringRedisTemplate stringRedisTemplate; + /** * 调用微信支付常见错误: * 1、验签错误 * 解决方案:1) 更改商户密钥5~6次;2) 调整xml报文的顺序排列;3) 如openid这种属性要严格区分大小写 */ - @ApiOperation(value = "微信小程序发起微信支付") + @Operation(summary = "微信小程序发起微信支付") @PostMapping(value = "/toPay4Applet") public BasicResult toPay4Applet(@RequestBody @Validated WxPayDto wxPayDto, HttpServletRequest request) { BasicData basicResult = new BasicData(); @@ -445,58 +452,70 @@ public void wxNotify(HttpServletRequest request, HttpServletResponse response) t String returnCode = (String) map.get("return_code"); if ("SUCCESS".equals(returnCode)) { //验证签名是否正确 - //支付回调这里不需要验证签名是否正确,目前回调的签名验证报签名错误 - - /*if (PayUtil.verify(PayUtil.createLinkString(map), (String) map.get("sign"), wxPayConfig.getMchKey(), "utf-8")) { - - }else{ + if (!PayUtil.verify(PayUtil.createLinkString(map), (String) map.get("sign"), wxPayConfig.getMchKey(), "utf-8")) { log.info("\n微信支付回调-验签失败"); - }*/ + resXml = "" + "" + + "" + " "; + return; + } log.info("\n微信支付回调-支付成功"); //out_trade_no_array暂不处理 String outTradeNo = (String) map.get("out_trade_no"); - MemberTradeRecord dbMemberTradeRecord = memberTradeRecordFeignApi.selectByOutTradeNo(outTradeNo).getData(); - if(dbMemberTradeRecord == null){ - log.error("该商户单号不存在,回调逻辑处理失败"); - return; - } - //为防止微信重复回调,需要对用户交易记录的状态进行判断 - if(dbMemberTradeRecord.getStatus() != Quantity.INT_1){ - log.error("微信重复回调,商户单号为" + outTradeNo); + // Redis 分布式锁 - 幂等控制 + String lockKey = "pay:callback:lock:" + outTradeNo; + Boolean isLocked = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "1", 3, TimeUnit.MINUTES); + if (Boolean.FALSE.equals(isLocked)) { + log.warn("订单 {} 正在处理或已处理,触发幂等拦截", outTradeNo); + resXml = ""; return; } - String transactionId = (String) map.get("transaction_id"); - //补填交易单号(支付平台的订单号),将交易状态改为支付成功 - MemberTradeRecord updateMemberTradeRecord = new MemberTradeRecord(); - updateMemberTradeRecord.setId(dbMemberTradeRecord.getId()); - updateMemberTradeRecord.setTradeNo(transactionId); - updateMemberTradeRecord.setStatus(Quantity.INT_2); - updateMemberTradeRecord.setUpdateTime(new Date()); - memberTradeRecordFeignApi.updateByPrimaryKeySelective(updateMemberTradeRecord); - - if(dbMemberTradeRecord.getType() == Quantity.INT_1){ - //交易类型为订单付款 - orderService.paymentNotify(outTradeNo); - - }else if(dbMemberTradeRecord.getType() == Quantity.INT_2){ - //交易类型为会员充值 - vipRechargeRecordFeignApi.updateByPayNotify(outTradeNo); - - }else if(dbMemberTradeRecord.getType() == Quantity.INT_3){ - //交易类型为自取订单改为配送 - orderService.paymentNotifyOfChangeToDelivery(outTradeNo); - - }else if(dbMemberTradeRecord.getType() == Quantity.INT_6){ - //交易类型为积分商城订单付款 - pointsMallOrderFeignApi.paymentNotify(outTradeNo); - } + try { + MemberTradeRecord dbMemberTradeRecord = memberTradeRecordFeignApi.selectByOutTradeNo(outTradeNo).getData(); + if(dbMemberTradeRecord == null){ + log.error("该商户单号不存在,回调逻辑处理失败"); + return; + } + //为防止微信重复回调,需要对用户交易记录的状态进行判断 + if(dbMemberTradeRecord.getStatus() != Quantity.INT_1){ + log.error("微信重复回调,商户单号为" + outTradeNo); + return; + } - //通知微信服务器已经支付成功 - resXml = "" + "" - + "" + " "; + String transactionId = (String) map.get("transaction_id"); + //补填交易单号(支付平台的订单号),将交易状态改为支付成功 + MemberTradeRecord updateMemberTradeRecord = new MemberTradeRecord(); + updateMemberTradeRecord.setId(dbMemberTradeRecord.getId()); + updateMemberTradeRecord.setTradeNo(transactionId); + updateMemberTradeRecord.setStatus(Quantity.INT_2); + updateMemberTradeRecord.setUpdateTime(new Date()); + memberTradeRecordFeignApi.updateByPrimaryKeySelective(updateMemberTradeRecord); + + if(dbMemberTradeRecord.getType() == Quantity.INT_1){ + //交易类型为订单付款 + orderService.paymentNotify(outTradeNo); + + }else if(dbMemberTradeRecord.getType() == Quantity.INT_2){ + //交易类型为会员充值 + vipRechargeRecordFeignApi.updateByPayNotify(outTradeNo); + + }else if(dbMemberTradeRecord.getType() == Quantity.INT_3){ + //交易类型为自取订单改为配送 + orderService.paymentNotifyOfChangeToDelivery(outTradeNo); + + }else if(dbMemberTradeRecord.getType() == Quantity.INT_6){ + //交易类型为积分商城订单付款 + pointsMallOrderFeignApi.paymentNotify(outTradeNo); + } + + //通知微信服务器已经支付成功 + resXml = "" + "" + + "" + " "; + } finally { + // 业务成功,锁保留到自然过期(3 分钟),防止微信短期并发重试 + } } else { resXml = "" + "" @@ -534,13 +553,12 @@ public void refundSuccessNotify(HttpServletRequest request, HttpServletResponse String returnCode = (String) map.get("return_code"); if ("SUCCESS".equals(returnCode)) { //验证签名是否正确 - //支付回调这里不需要验证签名是否正确,目前回调的签名验证报签名错误 - - /*if (PayUtil.verify(PayUtil.createLinkString(map), (String) map.get("sign"), wxPayConfig.getMchKey(), "utf-8")) { - - }else{ + if (!PayUtil.verify(PayUtil.createLinkString(map), (String) map.get("sign"), wxPayConfig.getMchKey(), "utf-8")) { log.info("\n微信退款回调-验签失败"); - }*/ + resXml = "" + "" + + "" + " "; + return; + } log.info("\n微信退款回调-支付成功"); log.debug("\n返回报文:" + map); @@ -555,36 +573,42 @@ public void refundSuccessNotify(HttpServletRequest request, HttpServletResponse //out_trade_no_array暂不处理 String outTradeNo = (String) map.get("out_trade_no"); - MemberTradeRecord dbMemberTradeRecord = memberTradeRecordFeignApi.selectByOutTradeNo(outTradeNo).getData(); - if(dbMemberTradeRecord == null){ - log.error("该商户单号不存在,回调逻辑处理失败"); - return; - } - //为防止微信重复回调,需要对用户交易记录的状态进行判断 - if(dbMemberTradeRecord.getStatus() != Quantity.INT_1){ - log.error("微信重复回调,商户单号为" + outTradeNo); + // Redis 分布式锁 - 幂等控制 + String lockKey = "pay:callback:lock:" + outTradeNo; + Boolean isLocked = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "1", 3, TimeUnit.MINUTES); + if (Boolean.FALSE.equals(isLocked)) { + log.warn("退款订单 {} 正在处理或已处理,触发幂等拦截", outTradeNo); + resXml = ""; return; } - String transactionId = (String) map.get("transaction_id"); - //补填交易单号(支付平台的订单号),将交易状态改为支付成功 - MemberTradeRecord updateMemberTradeRecord = new MemberTradeRecord(); - updateMemberTradeRecord.setId(dbMemberTradeRecord.getId()); - updateMemberTradeRecord.setTradeNo(transactionId); - updateMemberTradeRecord.setStatus(Quantity.INT_2); - updateMemberTradeRecord.setUpdateTime(new Date()); - memberTradeRecordFeignApi.updateByPrimaryKeySelective(updateMemberTradeRecord); + try { + MemberTradeRecord dbMemberTradeRecord = memberTradeRecordFeignApi.selectByOutTradeNo(outTradeNo).getData(); + if(dbMemberTradeRecord == null){ + log.error("该商户单号不存在,退款回调逻辑处理失败"); + return; + } + //退款回调时交易记录应为已支付状态(INT_2) + if(dbMemberTradeRecord.getStatus() != Quantity.INT_2){ + log.error("退款回调-交易记录状态异常,当前状态={},商户单号={}", dbMemberTradeRecord.getStatus(), outTradeNo); + resXml = "" + "" + + "" + " "; + return; + } - //交易类型为订单付款 - if(dbMemberTradeRecord.getType() == Quantity.INT_1){ - orderService.paymentNotify(outTradeNo); - }else if(dbMemberTradeRecord.getType() == Quantity.INT_3){ - orderService.paymentNotifyOfChangeToDelivery(outTradeNo); - } + //交易类型为订单付款/自取改配送,执行退款处理 + if(dbMemberTradeRecord.getType() == Quantity.INT_1){ + orderService.refundMerchantBalance(outTradeNo); + }else if(dbMemberTradeRecord.getType() == Quantity.INT_3){ + orderService.refundMerchantBalance(outTradeNo); + } - //通知微信服务器已经退款成功 - resXml = "" + "" - + "" + " "; + //通知微信服务器已经退款成功 + resXml = "" + "" + + "" + " "; + } finally { + // 业务成功,锁保留到自然过期 + } } else { resXml = "" + "" diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/internal/distributed_transaction/DR_OrderController.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/internal/distributed_transaction/DR_OrderController.java index 05cbd83..5146932 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/internal/distributed_transaction/DR_OrderController.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/member/internal/distributed_transaction/DR_OrderController.java @@ -4,7 +4,8 @@ import com.siam.package_order.entity.Order; import com.siam.package_order.model.param.OrderParam; import com.siam.package_order.service.OrderService; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.client.exception.MQBrokerException; import org.apache.rocketmq.client.exception.MQClientException; @@ -16,13 +17,13 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; +import jakarta.annotation.Resource; @Slf4j @RestController @RequestMapping(value = "/rest/member/pointsMall/order") @Transactional(rollbackFor = Exception.class) -@Api(tags = "订单模块相关接口", description = "OrderController") +@Tag(name = "订单模块相关接口", description = "OrderController") public class DR_OrderController { @Resource(name = "seata_OrderServiceImpl") diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/merchant/MerchantAppraiseController.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/merchant/MerchantAppraiseController.java index b348c5c..a4673f2 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/merchant/MerchantAppraiseController.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/merchant/MerchantAppraiseController.java @@ -14,7 +14,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.Map; /** diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/merchant/MerchantReplyController.java b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/merchant/MerchantReplyController.java index b732ae2..69e190f 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/controller/merchant/MerchantReplyController.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/controller/merchant/MerchantReplyController.java @@ -15,7 +15,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; /** * 商家端回复接口 diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/feign/OrderFeignProvider.java b/siam-order/order-provider/src/main/java/com/siam/package_order/feign/OrderFeignProvider.java index 44ac4cb..c8039f6 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/feign/OrderFeignProvider.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/feign/OrderFeignProvider.java @@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import java.math.BigDecimal; import java.util.Date; import java.util.Map; diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/model/dto/OrderPaySuccessMessage.java b/siam-order/order-provider/src/main/java/com/siam/package_order/model/dto/OrderPaySuccessMessage.java new file mode 100644 index 0000000..7d421ad --- /dev/null +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/model/dto/OrderPaySuccessMessage.java @@ -0,0 +1,19 @@ +package com.siam.package_order.model.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * 支付成功事务消息体 + */ +@Data +public class OrderPaySuccessMessage implements Serializable { + private Integer orderId; + private String orderNo; + private Integer shopId; + private Integer memberId; + private Integer shoppingWay; + private BigDecimal actualPrice; +} diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/mq_consumer/OrderConsumer.java b/siam-order/order-provider/src/main/java/com/siam/package_order/mq_consumer/OrderConsumer.java index 38d6d2d..21da405 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/mq_consumer/OrderConsumer.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/mq_consumer/OrderConsumer.java @@ -10,7 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import javax.annotation.Resource; +import jakarta.annotation.Resource; @Component @RocketMQMessageListener(consumerGroup = "orderConsumerGroup", topic = "TID_COMMON") diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/mq_listener/internal/OrderTransactionListener.java b/siam-order/order-provider/src/main/java/com/siam/package_order/mq_listener/internal/OrderTransactionListener.java index 92e2d14..a91c7d7 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/mq_listener/internal/OrderTransactionListener.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/mq_listener/internal/OrderTransactionListener.java @@ -1,59 +1,60 @@ package com.siam.package_order.mq_listener.internal; -import com.alibaba.fastjson.JSONObject; -import com.siam.package_order.entity.TransactionLog; -import com.siam.package_order.model.param.OrderParam; +import com.alibaba.fastjson.JSON; +import com.siam.package_common.constant.Quantity; +import com.siam.package_order.entity.Order; +import com.siam.package_order.mapper.OrderMapper; +import com.siam.package_order.model.dto.OrderPaySuccessMessage; import com.siam.package_order.service.OrderService; -import com.siam.package_order.service_impl.TransactionLogService; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.client.producer.LocalTransactionState; import org.apache.rocketmq.client.producer.TransactionListener; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageExt; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; -import javax.annotation.Resource; - +/** + * 支付成功事务消息监听器 + * executeLocalTransaction: 执行下游异步通知链路(公众号消息、语音提醒、打印) + * checkLocalTransaction: 回查订单支付状态,确认事务是否应提交 + */ @Component @Slf4j public class OrderTransactionListener implements TransactionListener { - @Resource(name = "rocketMQ_OrderServiceImpl") - private OrderService orderService; + @Autowired + private OrderMapper orderMapper; + @Lazy @Autowired - private TransactionLogService transactionLogService; + private OrderService orderService; @Override public LocalTransactionState executeLocalTransaction(Message message, Object o) { - log.info("[订单服务] 开始执行本地事务...."); - LocalTransactionState state; - //执行本地事务 + log.info("[订单服务] 开始执行支付成功本地事务,transId={}", message.getTransactionId()); try { - OrderParam param = JSONObject.parseObject(new String(message.getBody()), OrderParam.class); - orderService.insertByMQ(param, message.getTransactionId()); - state = LocalTransactionState.COMMIT_MESSAGE; - log.info("[订单服务] 本地事务已提交。{}", message.getTransactionId()); + OrderPaySuccessMessage msg = JSON.parseObject(new String(message.getBody()), OrderPaySuccessMessage.class); + orderService.executePaymentNotify(msg.getOrderId()); + log.info("[订单服务] 支付成功本地事务执行完成,transId={}", message.getTransactionId()); + return LocalTransactionState.COMMIT_MESSAGE; } catch (Exception e) { - log.error("[订单服务] 执行本地事务失败。{}", e.getMessage()); - state = LocalTransactionState.ROLLBACK_MESSAGE; - e.printStackTrace(); + log.error("[订单服务] 支付成功本地事务执行失败,{}", e.getMessage(), e); + return LocalTransactionState.ROLLBACK_MESSAGE; } - return state; } @Override public LocalTransactionState checkLocalTransaction(MessageExt messageExt) { - log.info("[订单服务] 开始回查本地事务...."); - LocalTransactionState state; - //如果本地事务存在,则事务提交成功 - TransactionLog transactionLog = transactionLogService.getById(messageExt.getTransactionId()); - if(transactionLog != null){ - state = LocalTransactionState.COMMIT_MESSAGE; - }else{ - state = LocalTransactionState.ROLLBACK_MESSAGE; + log.info("[订单服务] 开始回查支付本地事务,transId={}", messageExt.getTransactionId()); + OrderPaySuccessMessage msg = JSON.parseObject(new String(messageExt.getBody()), OrderPaySuccessMessage.class); + Order dbOrder = orderMapper.selectById(msg.getOrderId()); + if (dbOrder != null && (dbOrder.getStatus() == Quantity.INT_2 || dbOrder.getStatus() == Quantity.INT_4)) { + log.info("[订单服务] 回查确认:订单已支付,状态={}", dbOrder.getStatus()); + return LocalTransactionState.COMMIT_MESSAGE; } - return state; + log.warn("[订单服务] 回查失败:订单未支付或不存在,orderId={}", msg.getOrderId()); + return LocalTransactionState.ROLLBACK_MESSAGE; } -} \ No newline at end of file +} diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/mq_producer/internal/TransactionProducer.java b/siam-order/order-provider/src/main/java/com/siam/package_order/mq_producer/internal/TransactionProducer.java index 0335aa5..51f05dd 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/mq_producer/internal/TransactionProducer.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/mq_producer/internal/TransactionProducer.java @@ -6,9 +6,10 @@ import org.apache.rocketmq.client.producer.TransactionSendResult; import org.apache.rocketmq.common.message.Message; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -20,6 +21,7 @@ public class TransactionProducer { private TransactionMQProducer producer; + @Lazy @Autowired private OrderTransactionListener orderTransactionListener; diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/service/CommonService.java b/siam-order/order-provider/src/main/java/com/siam/package_order/service/CommonService.java index e793f72..6ea10d9 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/service/CommonService.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/service/CommonService.java @@ -11,11 +11,6 @@ public interface CommonService { */ BigDecimal selectDeliveryFee(BigDecimal lngA, BigDecimal latA, Integer shopId); - /** - * 计算订单配送费 - */ - BigDecimal selectDeliveryFee(String addressStr, Integer shopId); - /** * 计算两地的距离 / 用户当前定位与平台各店铺的距离 */ diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/service/OrderService.java b/siam-order/order-provider/src/main/java/com/siam/package_order/service/OrderService.java index d120128..99de54e 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/service/OrderService.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/service/OrderService.java @@ -32,8 +32,6 @@ public interface OrderService extends IService { * @return * @author 暹罗 */ - Order insertByMQ(OrderParam param, String transId) throws InterruptedException, RemotingException, MQClientException, MQBrokerException; - void cancelOrderByUnPaid(OrderParam param); void cancelOrderNoReason(OrderParam param) throws IOException; diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/CommonServiceImpl.java b/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/CommonServiceImpl.java index a513d7e..8f8b276 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/CommonServiceImpl.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/CommonServiceImpl.java @@ -81,11 +81,6 @@ public BigDecimal selectDeliveryFee(BigDecimal lngA, BigDecimal latA, Integer sh return deliveryFee; } - @Override - public BigDecimal selectDeliveryFee(String addressStr, Integer shopId) { - return null; - } - @Override public TravelingDistanceVo selectTravelingDistance(BigDecimal lngA, BigDecimal latA, BigDecimal lngB, BigDecimal latB) { TravelingDistanceVo travelingDistanceVo = new TravelingDistanceVo(); diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/OrderServiceImpl.java b/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/OrderServiceImpl.java index fda917c..1df8f9c 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/OrderServiceImpl.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/OrderServiceImpl.java @@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import io.seata.spring.annotation.GlobalTransactional; import com.siam.package_common.constant.BusinessType; import com.siam.package_common.constant.Quantity; import com.siam.package_common.constant.RocketMQConst; @@ -67,9 +68,10 @@ import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import java.io.IOException; import java.math.BigDecimal; import java.text.ParseException; @@ -166,6 +168,7 @@ public class OrderServiceImpl extends ServiceImpl implements @Autowired private OrderRefundProcessService orderRefundProcessService; + @Lazy @Autowired private WxPayService wxPayService; @@ -198,6 +201,7 @@ public void delete(OrderParam param){ orderMapper.updateById(updateOrder); } + @GlobalTransactional(name = "siam-order-create", rollbackFor = Exception.class) public Order insert(OrderParam param) { Member loginMember = memberSessionManager.getSession(TokenUtil.getToken()); @@ -367,8 +371,8 @@ private void saveOrderDetail(List orderDetailList, Order dbOrder, b } } - // 减少商品库存 (规格的库存该怎么去变化) - /*goodsService.decreaseStock(goodsId, number);*/ + // 减少商品库存 + goodsFeignApi.decreaseStock(goodsId, number); } } @@ -417,7 +421,7 @@ private String getOrderNo() { log.debug("\n获取订单编号..."); LambdaQueryWrapper orderLambdaQueryWrapper = new LambdaQueryWrapper<>(); orderLambdaQueryWrapper.eq(Order::getOrderNo, orderNo); - int result = orderMapper.selectCount(orderLambdaQueryWrapper); + long result = orderMapper.selectCount(orderLambdaQueryWrapper); if (result > 0) { orderNo = GenerateNo.getOrderNo(); } else { @@ -755,11 +759,6 @@ private void validateOrder(OrderParam param, Member loginMember) { } - @Override - public Order insertByMQ(OrderParam param, String transId) throws InterruptedException, RemotingException, MQClientException, MQBrokerException { - return null; - } - @Override public void cancelOrderByUnPaid(OrderParam param) { Member loginMember = memberSessionManager.getSession(TokenUtil.getToken()); @@ -931,16 +930,16 @@ private OrderRefund insertOrderRefundByNoReason(OrderParam param, Order dbOrder) } private void refundRestoreStock(int orderId) { -// //查询订单对应的订单商品详情数据 -// List orderDetailList = orderDetailService.selectByOrderId(orderId); -// -// //恢复订单对应的商品库存 (对应规格的库存怎么修改) -// for(OrderDetail orderDetail : orderDetailList){ -// int goodsId = orderDetail.getGoodsId(); -// int number = orderDetail.getNumber(); -// //增加商品库存 -// // goodsFeignApi.increaseStock(goodsId, number); -// } + //查询订单对应的订单商品详情数据 + List orderDetailList = orderDetailService.selectByOrderId(orderId); + + //恢复订单对应的商品库存 + for(OrderDetail orderDetail : orderDetailList){ + int goodsId = orderDetail.getGoodsId(); + int number = orderDetail.getNumber(); + //增加商品库存 + goodsFeignApi.increaseStock(goodsId, number); + } } @@ -1587,46 +1586,30 @@ public void paymentNotify(String outTradeNo) throws IOException, InterruptedExce return; } - Setting setting = settingFeignApi.selectCurrent().getData(); - - Shop dbShop = shopFeignApi.selectByPrimaryKey(dbOrder.getShopId()).getData(); - List orderDetailList = orderDetailService.selectByOrderId(dbOrder.getId()); - Member dbMember = memberFeignApi.selectByPrimaryKey(dbOrder.getMemberId()).getData(); - - Merchant dbMerchant = merchantFeignApi.selectByPrimaryKey(dbShop.getMerchantId()).getData(); - - // 1、修改订单状态 + // 1、修改订单状态(本地事务) handleOrderStatus(dbOrder, null); - // 6、处理商品信息 + // 2、更新商品销量(跨服务调用) handleGoodsInfo(orderDetailList); - // TODO - 插入平台抽佣账单记录 - - // todo - 发送微信公众平台消息给用户 - - // 7、发送微信公众平台消息给商家 - sendWxPublicPlatformMessageToMerchant(dbOrder, dbShop, orderDetailList); - - // 8、给商家端进行语音提醒、订单打印 - audioAndLocalPrint(dbShop, dbMerchant); - - // 9、打印小票 - basicPrintOrderReceipt(dbOrder, null, dbShop, orderDetailList); - - /*//加入MQ延时队列,订单支付超过1个小时 且 订单未取消/未申请退款,则将订单修改为已完成 - Message message01 = new Message("TID_COMMON", "AUTO_COMPLETED_ORDER", JSON.toJSONString(dbOrder).getBytes()); - message01.setDelayTimeLevel(RocketMQConst.DELAY_TIME_LEVEL_1H); - RocketMQTemplate rocketMQTemplate = applicationContext.getBean("rocketMQTemplate", RocketMQTemplate.class); - rocketMQTemplate.getProducer().send(message01);*/ - - /*//加入MQ延时队列,订单支付超过10分钟,状态还是处于待处理、待配送,则给与商家中心PC端订单即将超时语音提醒 - Message message02 = new Message("TID_COMMON", "REMIND_OVERTIME_ORDER", JSON.toJSONString(dbOrder).getBytes()); - message02.setDelayTimeLevel(RocketMQConst.DELAY_TIME_LEVEL_10M); - RocketMQTemplate rocketMQTemplate = applicationContext.getBean("rocketMQTemplate", RocketMQTemplate.class); - rocketMQTemplate.getProducer().send(message02);*/ + // 3、发送事务半消息,异步解耦下游通知链路 + try { + OrderPaySuccessMessage message = new OrderPaySuccessMessage(); + message.setOrderId(dbOrder.getId()); + message.setOrderNo(dbOrder.getOrderNo()); + message.setShopId(dbOrder.getShopId()); + message.setMemberId(dbOrder.getMemberId()); + message.setShoppingWay(dbOrder.getShoppingWay()); + message.setActualPrice(dbOrder.getActualPrice()); + TransactionProducer transactionProducer = applicationContext.getBean(TransactionProducer.class); + transactionProducer.send("ORDER_PAY_SUCCESS_TOPIC", JSON.toJSONString(message)); + log.info("支付成功事务消息已发送,订单号={}", outTradeNo); + } catch (Exception e) { + log.error("发送支付成功事务消息失败,订单号={}", outTradeNo, e); + // 不影响主流程,本地订单状态已更新 + } } private void handleCommission(Order dbOrder, Setting setting, Member dbMember) { @@ -2425,7 +2408,7 @@ public Map selectTabNumber(OrderParam param) { wrapper.in(Order::getStatus, statusList); wrapper.eq(Order::getMemberId, loginMember.getId()); wrapper.eq(Order::getIsDeleted, false); - int waitPaymentNumber = orderMapper.selectCount(wrapper); + long waitPaymentNumber = orderMapper.selectCount(wrapper); //待收货 4=待配送(已处理) 5=已配送 statusList = new ArrayList<>(); @@ -2435,7 +2418,7 @@ public Map selectTabNumber(OrderParam param) { wrapper.in(Order::getStatus, statusList); wrapper.eq(Order::getMemberId, loginMember.getId()); wrapper.eq(Order::getIsDeleted, false); - int waitReceivedNumber = orderMapper.selectCount(wrapper); + long waitReceivedNumber = orderMapper.selectCount(wrapper); //待自提 2=待处理 3=待自取(已处理) statusList = new ArrayList<>(); @@ -2445,7 +2428,7 @@ public Map selectTabNumber(OrderParam param) { wrapper.in(Order::getStatus, statusList); wrapper.eq(Order::getMemberId, loginMember.getId()); wrapper.eq(Order::getIsDeleted, false); - int waitPickedUp = orderMapper.selectCount(wrapper); + int waitPickedUp = orderMapper.selectCount(wrapper).intValue(); //退款/售后 状态处于7=售后处理中 8=已退款(废弃选项) statusList = new ArrayList<>(); @@ -2455,7 +2438,7 @@ public Map selectTabNumber(OrderParam param) { wrapper.in(Order::getStatus, statusList); wrapper.eq(Order::getMemberId, loginMember.getId()); wrapper.eq(Order::getIsDeleted, false); - int afterSalesNumber = orderMapper.selectCount(wrapper); + int afterSalesNumber = orderMapper.selectCount(wrapper).intValue(); Map map = new HashMap(); map.put("waitPaymentNumber", waitPaymentNumber); @@ -2484,28 +2467,28 @@ public Map selectAllTabWaitHandleNum(OrderParam param) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Order::getShoppingWay, Quantity.INT_1); wrapper.eq(Order::getStatus, Quantity.INT_2); - int waitHandleNum = orderMapper.selectCount(wrapper); + int waitHandleNum = orderMapper.selectCount(wrapper).intValue(); dataMap.put("waitHandleNum", waitHandleNum); //自取订单-待自取订单 wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Order::getShoppingWay, Quantity.INT_1); wrapper.eq(Order::getStatus, Quantity.INT_3); - int waitPickUpNum = orderMapper.selectCount(wrapper); + int waitPickUpNum = orderMapper.selectCount(wrapper).intValue(); dataMap.put("waitPickUpNum", waitPickUpNum); //外卖订单-待配送订单 wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Order::getShoppingWay, Quantity.INT_2); wrapper.eq(Order::getStatus, Quantity.INT_4); - int waitDeliveryNum = orderMapper.selectCount(wrapper); + int waitDeliveryNum = orderMapper.selectCount(wrapper).intValue(); dataMap.put("waitDeliveryNum", waitDeliveryNum); //外卖订单-已配送订单 wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Order::getShoppingWay, Quantity.INT_2); wrapper.eq(Order::getStatus, Quantity.INT_5); - int deliveredNum = orderMapper.selectCount(wrapper); + int deliveredNum = orderMapper.selectCount(wrapper).intValue(); dataMap.put("deliveredNum", deliveredNum); return dataMap; } @@ -3052,4 +3035,31 @@ public void allocatingFunds(Order dbOrder) { updateOrder.setIsPayToRiderFrozen(true); orderMapper.updateById(updateOrder); } + + /** + * 支付成功后的下游通知链路(由 RocketMQ 事务消息的本地事务回调触发) + * 包含:商家公众号通知、语音提醒、小票打印 + */ + public void executePaymentNotify(Integer orderId) { + Order dbOrder = orderMapper.selectById(orderId); + if (dbOrder == null) { + log.error("支付通知-订单不存在,orderId={}", orderId); + return; + } + + Setting setting = settingFeignApi.selectCurrent().getData(); + Shop dbShop = shopFeignApi.selectByPrimaryKey(dbOrder.getShopId()).getData(); + List orderDetailList = orderDetailService.selectByOrderId(dbOrder.getId()); + Member dbMember = memberFeignApi.selectByPrimaryKey(dbOrder.getMemberId()).getData(); + Merchant dbMerchant = merchantFeignApi.selectByPrimaryKey(dbShop.getMerchantId()).getData(); + + // 发送微信公众平台消息给商家 + sendWxPublicPlatformMessageToMerchant(dbOrder, dbShop, orderDetailList); + + // 给商家端进行语音提醒、订单打印 + audioAndLocalPrint(dbShop, dbMerchant); + + // 打印小票 + basicPrintOrderReceipt(dbOrder, null, dbShop, orderDetailList); + } } \ No newline at end of file diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/internal/RewardServiceImpl.java b/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/internal/RewardServiceImpl.java index b331951..d754b99 100644 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/internal/RewardServiceImpl.java +++ b/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/internal/RewardServiceImpl.java @@ -89,14 +89,14 @@ public void giveInviterReward(Integer inviterId, BigDecimal commissionAmount, In wrapper.ne(Order::getId, orderId); wrapper.gt(Order::getCreateTime, vipRechargeRecord.getCreateTime()); wrapper.notIn(Order::getStatus, excludeStatusList); - Integer count = orderMapper.selectCount(wrapper); + Long count = orderMapper.selectCount(wrapper); //查询积分商城的符合订单数 PointsMallOrderParam pointsMallOrderExample = new PointsMallOrderParam(); pointsMallOrderExample.setCreateTimeGreaterThan(vipRechargeRecord.getCreateTime()); pointsMallOrderExample.setExcludeStatusList(excludeStatusList); int count_pointsMall = pointsMallOrderFeignApi.countByExample(pointsMallOrderExample).getData(); - int total_count = count + count_pointsMall; + int total_count = count.intValue() + count_pointsMall; if(total_count > 0){ //不是第一笔订单,进行近30天是否有消费的条件判断 //近30天外卖系统支付成功的订单数 @@ -105,7 +105,7 @@ public void giveInviterReward(Integer inviterId, BigDecimal commissionAmount, In param.setExcludeOrderId(orderId); param.setStartTime(DateUtilsExtend.getFrontDay(DateUtilsExtend.getDayEnd(), 30)); param.setEndTime(DateUtilsExtend.getDayEnd()); - count = this.orderMapper.selectCountPaid(param); + count = Long.valueOf(this.orderMapper.selectCountPaid(param)); count = count!=null ? count : 0; //近30天积分商城支付成功的订单数 @@ -115,7 +115,7 @@ public void giveInviterReward(Integer inviterId, BigDecimal commissionAmount, In pointsMallOrder.setEndTime(DateUtilsExtend.getDayEnd()); count_pointsMall = this.pointsMallOrderFeignApi.selectCountPaid(pointsMallOrder).getData(); - total_count = count + count_pointsMall; + total_count = count.intValue() + count_pointsMall; if(total_count == 0){ //TODO-可以建立一张表把这些信息存下来的 log.info("\n\nid为" + inviterId + "的邀请人在近30天内无消费,不给予佣金奖励"); @@ -218,13 +218,13 @@ public String selectCommissionReward(OrderParam param) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.gt(Order::getCreateTime, vipRechargeRecord.getCreateTime()); wrapper.notIn(Order::getStatus, excludeStatusList); - int count = orderMapper.selectCount(wrapper); + long count = orderMapper.selectCount(wrapper); //查询积分商城的符合订单数 PointsMallOrderParam pointsMallOrderExample = new PointsMallOrderParam(); pointsMallOrderExample.setCreateTimeGreaterThan(vipRechargeRecord.getCreateTime()); pointsMallOrderExample.setExcludeStatusList(excludeStatusList); int count_pointsMall = pointsMallOrderFeignApi.countByExample(pointsMallOrderExample).getData(); - int total_count = count + count_pointsMall; + int total_count = (int) count + count_pointsMall; if(total_count > 0){ //不是第一笔订单,进行近30天是否有消费的条件判断 //近30天外卖系统支付成功的订单数 @@ -240,7 +240,7 @@ public String selectCommissionReward(OrderParam param) { pointsMallOrder.setEndTime(DateUtilsExtend.getDayEnd()); count_pointsMall = this.pointsMallOrderFeignApi.selectCountPaid(pointsMallOrder).getData(); - total_count = count + count_pointsMall; + total_count = (int) count + count_pointsMall; if(total_count == 0){ //TODO-可以建立一张表把这些信息存下来的 /*text = "您在近30天内无消费,该笔订单完成后再次消费,您可得到"+ commissionAmount +"元返利";*/ diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/internal/distributed_transaction/LocalMsg_OrderServiceImpl.java b/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/internal/distributed_transaction/LocalMsg_OrderServiceImpl.java deleted file mode 100644 index a8f2483..0000000 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/internal/distributed_transaction/LocalMsg_OrderServiceImpl.java +++ /dev/null @@ -1,616 +0,0 @@ -package com.siam.package_order.service_impl.internal.distributed_transaction; - -import com.baomidou.mybatisplus.core.conditions.Wrapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.siam.package_common.util.RedisUtils; -import com.siam.package_goods.feign.ShoppingCartFeignApi; -import com.siam.package_order.entity.Order; -import com.siam.package_order.mapper.OrderMapper; -import com.siam.package_order.model.example.OrderExample; -import com.siam.package_order.model.param.OrderParam; -import com.siam.package_order.model.vo.OrderVo; -import com.siam.package_order.model.vo.OrderVo2; -import com.siam.package_order.service.OrderDetailService; -import com.siam.package_order.service.OrderService; -import com.siam.package_promotion.feign.CouponsMemberRelationFeignApi; -import com.siam.package_user.auth.cache.MemberSessionManager; -import com.siam.package_user.feign.DeliveryAddressFeignApi; -import com.siam.package_user.feign.MemberFeignApi; -import lombok.extern.slf4j.Slf4j; -import org.apache.rocketmq.client.exception.MQBrokerException; -import org.apache.rocketmq.client.exception.MQClientException; -import org.apache.rocketmq.remoting.exception.RemotingException; -import org.apache.rocketmq.spring.core.RocketMQTemplate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; - -import java.io.IOException; -import java.io.Serializable; -import java.math.BigDecimal; -import java.text.ParseException; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -/** - * 分布式事务-本地消息表 - * - * @return - * @author 暹罗 - */ -@Slf4j -@Service -public class LocalMsg_OrderServiceImpl implements OrderService { - - public static final String USER_ORDER_TOKEN_PREFIX = "order:token:"; - - @Autowired - private OrderMapper orderMapper; - - @Autowired - private OrderDetailService orderDetailService; - - @Autowired - private MemberFeignApi memberFeignApi; - - @Autowired - private DeliveryAddressFeignApi deliveryAddressFeignApi; - - @Autowired - private MemberSessionManager memberSessionManager; - - @Autowired - private ShoppingCartFeignApi shoppingCartFeignApi; - - @Autowired - private CouponsMemberRelationFeignApi couponsMemberRelationFeignApi; - - @Autowired - private ApplicationContext applicationContext; - - @Autowired - private RedisUtils redisUtils; - - @Autowired - private RedisTemplate redisTemplate; - - @Override - public void delete(OrderParam param) { - - } - - @Override - public Order insert(OrderParam param) { -// //TODO(MARK) - 购物车下单、直接购买两种形式可以不拆分成两个接口 -// //TODO(MARK) - 系统默认免运费 -// param.setDeliveryFee(BigDecimal.ZERO); -// Member loginMember = memberSessionManager.getSession(TokenUtil.getToken()); -// Member dbMember = memberFeignApi.selectByPrimaryKey(loginMember.getId()).getData(); -// -//// //校验防重令牌是否正确 -- 保证该接口的幂等性 -//// String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; -//// Long result = (Long) redisTemplate.execute(new DefaultRedisScript(script, Long.class), Arrays.asList(USER_ORDER_TOKEN_PREFIX + loginMember.getId()), param.getOrderToken()); -//// if(result == 0){ -//// throw new StoneCustomerException("请勿重复提交"); -//// } -// -// //校验:如果是从购物车下单的 那么需要校验购物车数据是否存在 以及购物车数据是否属于当前登录用户 -// if(param.getShoppingCartIdList()!=null && !param.getShoppingCartIdList().isEmpty()){ -// int count = shoppingCartFeignApi.countByIdListAndMemberId(param.getShoppingCartIdList(), loginMember.getId()).getData(); -// if(count != param.getShoppingCartIdList().size()){ -// throw new StoneCustomerException("购物车数据异常,请刷新页面重新下单"); -// } -// } -// -// //根据收货地址id回写联系人信息 -// DeliveryAddress dbDeliveryAddress = deliveryAddressFeignApi.selectByPrimaryKey(param.getDeliveryAddressId()); -// if(dbDeliveryAddress == null){ -// throw new StoneCustomerException("该收货地址不存在"); -// } -// param.setContactRealname(dbDeliveryAddress.getRealname()); -// param.setContactPhone(dbDeliveryAddress.getPhone()); -// param.setContactProvince(dbDeliveryAddress.getProvince()); -// param.setContactCity(dbDeliveryAddress.getCity()); -// param.setContactArea(dbDeliveryAddress.getArea()); -// param.setContactStreet(dbDeliveryAddress.getStreet()); -// param.setContactSex(dbDeliveryAddress.getSex()); -// param.setContactHouseNumber(dbDeliveryAddress.getHouseNumber()); -// param.setContactLongitude(dbDeliveryAddress.getLongitude()); -// param.setContactLatitude(dbDeliveryAddress.getLatitude()); -// -//// //1、校验前端的实付款金额是否正确 -//// this.validatePrice(param); -// -// //生成订单编号 -// String orderNo = GenerateNo.getOrderNo(); -// //生成订单取餐号 -// Integer queueNo = getNextQueueNo(); -// //生成支付截止时间(五分钟内未付款的订单会被自动关闭) -// Date paymentDeadline = DateUtilsPlus.addMinutes(new Date(), Quantity.INT_5); -// -// //2、添加订单记录 -// Order insertOrder = new Order(); -// insertOrder.setMemberId(loginMember.getId()); -// insertOrder.setOrderNo(orderNo); -// insertOrder.setGoodsTotalQuantity(param.getGoodsTotalQuantity()); -// insertOrder.setGoodsTotalPrice(param.getGoodsTotalPrice()); -// insertOrder.setDeliveryFee(param.getDeliveryFee()); -// insertOrder.setActualPrice(param.getActualPrice()); -// insertOrder.setShoppingWay(Quantity.INT_2); -// insertOrder.setDeliveryAddressId(param.getDeliveryAddressId()); -// insertOrder.setContactRealname(param.getContactRealname()); -// insertOrder.setContactPhone(param.getContactPhone()); -// insertOrder.setContactProvince(param.getContactProvince()); -// insertOrder.setContactCity(param.getContactCity()); -// insertOrder.setContactArea(param.getContactArea()); -// insertOrder.setContactStreet(param.getContactStreet()); -// insertOrder.setContactSex(param.getContactSex()); -// insertOrder.setTradeId(null); -// insertOrder.setRemark(param.getRemark()); -// insertOrder.setDescription(param.getDescription()); -// insertOrder.setStatus(Quantity.INT_1); -// insertOrder.setOrderLogisticsId(null); -// insertOrder.setIsInvoice(false); -// insertOrder.setInvoiceId(null); -// insertOrder.setIsDeleted(false); -// insertOrder.setShopName(param.getShopName()); -// insertOrder.setShopAddress(param.getShopAddress()); -// insertOrder.setCancelReason(null); -// insertOrder.setPaymentDeadline(paymentDeadline); -// insertOrder.setCreateTime(new Date()); -// insertOrder.setUpdateTime(new Date()); -// insertOrder.setQueueNo(queueNo); -// insertOrder.setFullReductionRuleId(param.getFullReductionRuleId()); -// insertOrder.setFullReductionRuleDescription(param.getFullReductionRuleDescription()); -// insertOrder.setCouponsId(param.getCouponsId()); -// insertOrder.setCouponsMemberRelationId(param.getCouponsMemberRelationId()); -// insertOrder.setCouponsDescription(param.getCouponsDescription()); -// insertOrder.setLimitedPrice(param.getLimitedPrice()); -// insertOrder.setReducedPrice(param.getReducedPrice()); -// insertOrder.setCouponsDiscountPrice(param.getCouponsDiscountPrice()); -// insertOrder.setDeliveryWay(param.getDeliveryWay()); -// insertOrder.setIsPayToMerchant(false); -// insertOrder.setBeforeReducedDeliveryFee(param.getBeforeReducedDeliveryFee()); -// insertOrder.setContactHouseNumber(param.getContactHouseNumber()); -// insertOrder.setContactLongitude(param.getContactLongitude()); -// insertOrder.setContactLatitude(param.getContactLatitude()); -// insertOrder.setFirstGoodsMainImage(param.getFirstGoodsMainImage()); -// orderMapper.insert(insertOrder); -// -// //获取最新订单对象 -// Order dbOrder = orderMapper.selectById(insertOrder.getId()); -// -// //3、添加订单商品详情记录 -// for(OrderDetail orderDetail : param.getOrderDetailList()){ -// // 添加订单商品详情记录 -// OrderDetail insertDetail = new OrderDetail(); -// insertDetail.setOrderId(dbOrder.getId()); -// insertDetail.setGoodsId(orderDetail.getGoodsId()); -// insertDetail.setGoodsName(orderDetail.getGoodsName()); -// insertDetail.setMainImage(orderDetail.getMainImage()); -// insertDetail.setSpecList(orderDetail.getSpecList()); -// insertDetail.setPrice(orderDetail.getPrice()); -// insertDetail.setNumber(orderDetail.getNumber()); -// insertDetail.setSubtotal(orderDetail.getSubtotal()); -// if(orderDetail.getIsUsedCoupons() != null){ -// insertDetail.setIsUsedCoupons(orderDetail.getIsUsedCoupons()); -// insertDetail.setCouponsDiscountPrice(orderDetail.getCouponsDiscountPrice()); -// insertDetail.setAfterCouponsDiscountPrice(orderDetail.getPrice().subtract(orderDetail.getCouponsDiscountPrice())); -// } -// insertDetail.setIsDeleted(false); -// orderDetailService.insertSelective(insertDetail); -// -// //TODO - 减少商品库存 (规格的库存该怎么去变化) -// /*goodsFeignApi.decreaseStock(goodsId, number);*/ -// } -// -// //保存本地消息表 -// LocalMsg localMsg = new LocalMsg(); -// localMsg.setId(dbOrder.getId().toString()); -// localMsg.setContent(JSON.toJSONString(dbOrder)); -// localMsg.setStatus(0); -// localMsg.setSendTime(new Date()); -// List localMsgList = new ArrayList<>(); -// if(redisUtils.hasKey("localMsgList")){ -// localMsgList = (List) JsonUtils.toObject(redisUtils.get("localMsgList").toString(), List.class); -// } -// localMsgList.add(localMsg); -// redisUtils.set("localMsgList", localMsgList); -// -// //4、如果是从购物车下单的 那么下单成功后需要删除购物车数据 注意用批量删除 -// if(param.getShoppingCartIdList()!=null && param.getShoppingCartIdList().size()>0){ -// shoppingCartFeignApi.batchDeleteByIdList(param.getShoppingCartIdList()); -// } -// -// //5、修改是否为新用户标识 -// if(dbMember.getIsNewPeople()){ -// dbMember.setIsNewPeople(false); -// dbMember.setIsRemindNewPeople(false); -// memberFeignApi.updateByPrimaryKeySelective(dbMember); -// } -// -// //模拟程序出错 -//// int i = 10 / 0; -// -// //6、更新优惠卷的使用状态 -// if (param.getCouponsMemberRelationId() != null) { -// couponsMemberRelationFeignApi.updateCouponsUsed(param.getCouponsMemberRelationId(),true); -// } -// -// //加入MQ延时队列,检测并关闭超时未支付的订单,5分钟 -// Message message = new Message("TID_COMMON_MALL", "CLOSE_OVERDUE_ORDER", JSON.toJSONString(dbOrder).getBytes()); -// message.setDelayTimeLevel(RocketMQConst.DELAY_TIME_LEVEL_5M); -// RocketMQTemplate rocketMQTemplate = applicationContext.getBean("rocketMQTemplate", RocketMQTemplate.class); -// rocketMQTemplate.getProducer().send(message); -// -// return dbOrder; - - return null; - } - - @Override - public Order insertByMQ(OrderParam param, String transId) throws InterruptedException, RemotingException, MQClientException, MQBrokerException { - return null; - } - - @Override - public void cancelOrderByUnPaid(OrderParam param) { - - } - - @Override - public void cancelOrderNoReason(OrderParam param) throws IOException { - - } - - @Override - public void applyRefund(OrderParam param) throws IOException { - - } - - @Override - public void confirmReceipt(OrderParam param) { - - } - - @Override - public Order selectByPrimaryKey(Integer id) { - return null; - } - - @Override - public void updateByPrimaryKeySelective(Order record) { - - } - - @Override - public Page getListByPageWithAsc(OrderParam param) { - return null; - } - - @Override - public Page> getListByPageWithDesc(OrderParam param) { - return null; - } - - @Override - public Order selectByOrderNo(String orderNo) { - return null; - } - - @Override - public void closeOverdueOrder(Integer id) { - - } - - @Override - public void autoCompletedOrder(Integer id) { - - } - - @Override - public void printRceceipts(Integer id) { - - } - - @Override - public int batchUpdateIsPrintedTrue(List idList) { - return 0; - } - - @Override - public Integer getNextQueueNo() { - return null; - } - - @Override - public Page getListByTodayOrderWithAsc(OrderParam param) { - return null; - } - - @Override - public void paymentNotify(String outTradeNo) throws IOException, InterruptedException, RemotingException, MQClientException, MQBrokerException { - - } - - @Override - public void paymentNotifyOfChangeToDelivery(String changeToDeliveryOutTradeNo) { - - } - - @Override - public Map countOrder(OrderParam order) { - return null; - } - - @Override - public int selectLatelyMonthlySalesByShopId(Date startTime, Date endTime, Integer shopId) { - return 0; - } - - @Override - public BigDecimal selectSumMerchantIncome(OrderParam param) { - return null; - } - - @Override - public BigDecimal selectSumActualPrice(OrderParam param) { - return null; - } - - @Override - public int selectCountCompleted(OrderParam param) { - return 0; - } - - @Override - public int selectCountPaid(OrderParam param) { - return 0; - } - - @Override - public boolean getIsAllowCancelNoReason(OrderParam order) { - return false; - } - - @Override - public boolean getIsAllowApplyRefund(OrderParam order) { - return false; - } - - @Override - public Page getAfterSalesListByPageWithAsc(OrderParam param) { - return null; - } - - @Override - public void updatePayOrderFrozenBalanceOfMerchant() { - - } - - @Override - public void remindOvertimeOrder(Integer id) throws IOException { - - } - - @Override - public List> selectStatisticOrder(Integer shopId) { - return null; - } - - @Override - public String selectStartDateOrder(Integer shopId) { - return null; - } - - @Override - public int selectCountPayers(OrderParam param) { - return 0; - } - - @Override - public int selectCountOrderPeoples(OrderParam param) { - return 0; - } - - @Override - public void refundMerchantBalance(String out_trade_no) { - - } - - @Override - public Map selectSumField(OrderParam order) { - return null; - } - - @Override - public int selectCountUnCompleted(OrderParam order) { - return 0; - } - - @Override - public int selectCountWaitHandle(OrderParam order) { - return 0; - } - - @Override - public OrderVo selectById(OrderParam param) { - return null; - } - - @Override - public OrderVo2 selectRefundProcess(OrderParam param) { - return null; - } - - @Override - public Map selectTabNumber(OrderParam param) { - return null; - } - - @Override - public void batchUpdateIsPrintedTrue(OrderParam param) { - - } - - @Override - public Map selectAllTabWaitHandleNum(OrderParam param) { - return null; - } - - @Override - public List waitPrintOrderList(OrderParam param) { - return null; - } - - @Override - public void auditAfterSalesOrderByAdmin(OrderParam param) { - - } - - @Override - public void auditAfterSalesOrderByMerchant(OrderParam param) { - - } - - @Override - public Map statistic(OrderParam param) throws ParseException { - return null; - } - - @Override - public void printOrderReceipt(Order dbOrder, String printType) { - - } - - @Override - public void allocatingFunds(Order dbOrder) { - - } - - @Override - public boolean save(Order entity) { - return false; - } - - @Override - public boolean saveBatch(Collection entityList, int batchSize) { - return false; - } - - @Override - public boolean saveOrUpdateBatch(Collection entityList, int batchSize) { - return false; - } - - @Override - public boolean removeById(Serializable id) { - return false; - } - - @Override - public boolean removeByMap(Map columnMap) { - return false; - } - - @Override - public boolean remove(Wrapper queryWrapper) { - return false; - } - - @Override - public boolean removeByIds(Collection idList) { - return false; - } - - @Override - public boolean updateById(Order entity) { - return false; - } - - @Override - public boolean update(Order entity, Wrapper updateWrapper) { - return false; - } - - @Override - public boolean updateBatchById(Collection entityList, int batchSize) { - return false; - } - - @Override - public boolean saveOrUpdate(Order entity) { - return false; - } - - @Override - public Order getById(Serializable id) { - return null; - } - - @Override - public List listByIds(Collection idList) { - return null; - } - - @Override - public List listByMap(Map columnMap) { - return null; - } - - @Override - public Order getOne(Wrapper queryWrapper, boolean throwEx) { - return null; - } - - @Override - public Map getMap(Wrapper queryWrapper) { - return null; - } - - @Override - public V getObj(Wrapper queryWrapper, Function mapper) { - return null; - } - - @Override - public int count(Wrapper queryWrapper) { - return 0; - } - - @Override - public List list(Wrapper queryWrapper) { - return null; - } - - @Override - public > E page(E page, Wrapper queryWrapper) { - return null; - } - - @Override - public List> listMaps(Wrapper queryWrapper) { - return null; - } - - @Override - public List listObjs(Wrapper queryWrapper, Function mapper) { - return null; - } - - @Override - public >> E pageMaps(E page, Wrapper queryWrapper) { - return null; - } - - @Override - public BaseMapper getBaseMapper() { - return null; - } -} \ No newline at end of file diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/internal/distributed_transaction/RocketMQ_OrderServiceImpl.java b/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/internal/distributed_transaction/RocketMQ_OrderServiceImpl.java deleted file mode 100644 index eac07ea..0000000 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/internal/distributed_transaction/RocketMQ_OrderServiceImpl.java +++ /dev/null @@ -1,689 +0,0 @@ -package com.siam.package_order.service_impl.internal.distributed_transaction; - -import com.alibaba.fastjson.JSON; -import com.baomidou.mybatisplus.core.conditions.Wrapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.siam.package_common.util.RedisUtils; -import com.siam.package_goods.feign.GoodsFeignApi; -import com.siam.package_goods.feign.GoodsSpecificationOptionFeignApi; -import com.siam.package_goods.feign.ShoppingCartFeignApi; -import com.siam.package_order.controller.member.WxPayService; -import com.siam.package_order.entity.Order; -import com.siam.package_order.mapper.OrderMapper; -import com.siam.package_order.model.example.OrderExample; -import com.siam.package_order.model.param.OrderParam; -import com.siam.package_order.model.vo.OrderVo; -import com.siam.package_order.model.vo.OrderVo2; -import com.siam.package_order.mq_producer.internal.TransactionProducer; -import com.siam.package_order.service.*; -import com.siam.package_order.service_impl.TransactionLogService; -import com.siam.package_promotion.feign.CouponsFeignApi; -import com.siam.package_promotion.feign.CouponsGoodsRelationFeignApi; -import com.siam.package_promotion.feign.CouponsMemberRelationFeignApi; -import com.siam.package_promotion.feign.FullReductionRuleFeignApi; -import com.siam.package_user.auth.cache.MemberSessionManager; -import com.siam.package_user.feign.*; -import com.siam.package_user.feign.internal.VipRechargeRecordFeignApi; -import com.siam.package_util.feign.SettingFeignApi; -import com.siam.package_weixin_basic.service.WxNotifyService; -import com.siam.package_weixin_basic.service.WxPublicPlatformNotifyService; -import lombok.extern.slf4j.Slf4j; -import org.apache.rocketmq.client.exception.MQBrokerException; -import org.apache.rocketmq.client.exception.MQClientException; -import org.apache.rocketmq.remoting.exception.RemotingException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; - -import javax.annotation.Resource; -import java.io.IOException; -import java.io.Serializable; -import java.math.BigDecimal; -import java.text.ParseException; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -/** - * 分布式事务-RocketMQ事务消息 - * - * @return - * @author 暹罗 - */ -@Slf4j -@Service -public class RocketMQ_OrderServiceImpl implements OrderService { - - public static final String USER_ORDER_TOKEN_PREFIX = "order:token:"; - - @Autowired - private OrderMapper orderMapper; - - @Autowired - private OrderDetailService orderDetailService; - - @Autowired - private SettingFeignApi settingFeignApi; - - @Autowired - private MemberBillingRecordFeignApi memberBillingRecordFeignApi; - - @Autowired - private MemberFeignApi memberFeignApi; - - @Autowired - private MemberTradeRecordFeignApi memberTradeRecordFeignApi; - - @Autowired - private DeliveryAddressFeignApi deliveryAddressFeignApi; - - @Autowired - private WxNotifyService wxNotifyService; - - @Autowired - private WxPublicPlatformNotifyService wxPublicPlatformNotifyService; - - @Autowired - private OrderRefundService orderRefundService; - - @Autowired - private MemberInviteRelationFeignApi memberInviteRelationFeignApi; - - @Resource(name = "orderServiceImpl") - private OrderService orderService; - - @Autowired - private VipRechargeRecordFeignApi vipRechargeRecordFeignApi; - - @Autowired - private OrderRefundGoodsService orderRefundGoodsService; - - @Autowired - private OrderRefundProcessService orderRefundProcessService; - - @Autowired - private WxPayService wxPayService; - - @Autowired - private MemberSessionManager memberSessionManager; - - @Autowired - private CommonService commonService; - - @Autowired - private ShoppingCartFeignApi shoppingCartFeignApi; - - @Autowired - private GoodsFeignApi goodsFeignApi; - - @Autowired - private GoodsSpecificationOptionFeignApi goodsSpecificationOptionFeignApi; - - @Autowired - private CouponsMemberRelationFeignApi couponsMemberRelationFeignApi; - - @Autowired - private CouponsFeignApi couponsFeignApi; - - @Autowired - private CouponsGoodsRelationFeignApi couponsGoodsRelationFeignApi; - - @Autowired - private FullReductionRuleFeignApi fullReductionRuleFeignApi; - - @Autowired - private ApplicationContext applicationContext; - - @Autowired - private RedisUtils redisUtils; - - @Autowired - private RedisTemplate redisTemplate; - - @Autowired - private TransactionProducer pointsMallTransactionProducer; - - @Autowired - private TransactionLogService transactionLogService; - - @Override - public void delete(OrderParam param) { - - } - - @Override - public Order insert(OrderParam param) { - try { - pointsMallTransactionProducer.send("order", JSON.toJSONString(param)); - } catch (MQClientException e) { - e.printStackTrace(); - } - //TODO - 返回订单信息(订单id) - return null; - } - - @Override - public Order insertByMQ(OrderParam param, String transId) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { -// //TODO(MARK) - 购物车下单、直接购买两种形式可以不拆分成两个接口 -// //TODO(MARK) - 系统默认免运费 -// param.setDeliveryFee(BigDecimal.ZERO); -//// Member loginMember = memberSessionManager.getSession(TokenUtil.getToken()); -//// Member dbMember = memberFeignApi.selectByPrimaryKey(loginMember.getId()); -// -// Member dbMember = memberFeignApi.selectByPrimaryKey(2).getData(); -// -//// //校验防重令牌是否正确 -- 保证该接口的幂等性 -//// String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; -//// Long result = (Long) redisTemplate.execute(new DefaultRedisScript(script, Long.class), Arrays.asList(USER_ORDER_TOKEN_PREFIX + loginMember.getId()), param.getOrderToken()); -//// if(result == 0){ -//// throw new StoneCustomerException("请勿重复提交"); -//// } -// -// //校验:如果是从购物车下单的 那么需要校验购物车数据是否存在 以及购物车数据是否属于当前登录用户 -// if(param.getShoppingCartIdList()!=null && !param.getShoppingCartIdList().isEmpty()){ -// int count = shoppingCartFeignApi.countByIdListAndMemberId(param.getShoppingCartIdList(), dbMember.getId()).getData(); -// if(count != param.getShoppingCartIdList().size()){ -// throw new StoneCustomerException("购物车数据异常,请刷新页面重新下单"); -// } -// } -// -// //根据收货地址id回写联系人信息 -// DeliveryAddress dbDeliveryAddress = deliveryAddressFeignApi.selectByPrimaryKey(param.getDeliveryAddressId()); -// if(dbDeliveryAddress == null){ -// throw new StoneCustomerException("该收货地址不存在"); -// } -// param.setContactRealname(dbDeliveryAddress.getRealname()); -// param.setContactPhone(dbDeliveryAddress.getPhone()); -// param.setContactProvince(dbDeliveryAddress.getProvince()); -// param.setContactCity(dbDeliveryAddress.getCity()); -// param.setContactArea(dbDeliveryAddress.getArea()); -// param.setContactStreet(dbDeliveryAddress.getStreet()); -// param.setContactSex(dbDeliveryAddress.getSex()); -// param.setContactHouseNumber(dbDeliveryAddress.getHouseNumber()); -// param.setContactLongitude(dbDeliveryAddress.getLongitude()); -// param.setContactLatitude(dbDeliveryAddress.getLatitude()); -// -// //1、校验前端的实付款金额是否正确 -// this.validatePrice(param); -// -// //生成订单编号 -// String orderNo = GenerateNo.getOrderNo(); -// //生成订单取餐号 -// Integer queueNo = getNextQueueNo(); -// //生成支付截止时间(五分钟内未付款的订单会被自动关闭) -// Date paymentDeadline = DateUtilsPlus.addMinutes(new Date(), Quantity.INT_5); -// -// //2、添加订单记录 -// Order insertOrder = new Order(); -// insertOrder.setMemberId(dbMember.getId()); -// insertOrder.setOrderNo(orderNo); -// insertOrder.setGoodsTotalQuantity(param.getGoodsTotalQuantity()); -// insertOrder.setGoodsTotalPrice(param.getGoodsTotalPrice()); -// insertOrder.setDeliveryFee(param.getDeliveryFee()); -// insertOrder.setActualPrice(param.getActualPrice()); -// insertOrder.setShoppingWay(Quantity.INT_2); -// insertOrder.setDeliveryAddressId(param.getDeliveryAddressId()); -// insertOrder.setContactRealname(param.getContactRealname()); -// insertOrder.setContactPhone(param.getContactPhone()); -// insertOrder.setContactProvince(param.getContactProvince()); -// insertOrder.setContactCity(param.getContactCity()); -// insertOrder.setContactArea(param.getContactArea()); -// insertOrder.setContactStreet(param.getContactStreet()); -// insertOrder.setContactSex(param.getContactSex()); -// insertOrder.setTradeId(null); -// insertOrder.setRemark(param.getRemark()); -// insertOrder.setDescription(param.getDescription()); -// insertOrder.setStatus(Quantity.INT_1); -// insertOrder.setOrderLogisticsId(null); -// insertOrder.setIsInvoice(false); -// insertOrder.setInvoiceId(null); -// insertOrder.setIsDeleted(false); -// insertOrder.setShopName(param.getShopName()); -// insertOrder.setShopAddress(param.getShopAddress()); -// insertOrder.setCancelReason(null); -// insertOrder.setPaymentDeadline(paymentDeadline); -// insertOrder.setCreateTime(new Date()); -// insertOrder.setUpdateTime(new Date()); -// insertOrder.setQueueNo(queueNo); -// insertOrder.setFullReductionRuleId(param.getFullReductionRuleId()); -// insertOrder.setFullReductionRuleDescription(param.getFullReductionRuleDescription()); -// insertOrder.setCouponsId(param.getCouponsId()); -// insertOrder.setCouponsMemberRelationId(param.getCouponsMemberRelationId()); -// insertOrder.setCouponsDescription(param.getCouponsDescription()); -// insertOrder.setLimitedPrice(param.getLimitedPrice()); -// insertOrder.setReducedPrice(param.getReducedPrice()); -// insertOrder.setCouponsDiscountPrice(param.getCouponsDiscountPrice()); -// insertOrder.setDeliveryWay(param.getDeliveryWay()); -// insertOrder.setIsPayToMerchant(false); -// insertOrder.setBeforeReducedDeliveryFee(param.getBeforeReducedDeliveryFee()); -// insertOrder.setContactHouseNumber(param.getContactHouseNumber()); -// insertOrder.setContactLongitude(param.getContactLongitude()); -// insertOrder.setContactLatitude(param.getContactLatitude()); -// insertOrder.setFirstGoodsMainImage(param.getFirstGoodsMainImage()); -// orderMapper.insert(insertOrder); -// -// //获取最新订单对象 -// Order dbOrder = orderMapper.selectById(insertOrder.getId()); -// -// //3、添加订单商品详情记录 -// for(OrderDetail orderDetail : param.getOrderDetailList()){ -// // 添加订单商品详情记录 -// OrderDetail insertDetail = new OrderDetail(); -// insertDetail.setOrderId(dbOrder.getId()); -// insertDetail.setGoodsId(orderDetail.getGoodsId()); -// insertDetail.setGoodsName(orderDetail.getGoodsName()); -// insertDetail.setMainImage(orderDetail.getMainImage()); -// insertDetail.setSpecList(orderDetail.getSpecList()); -// insertDetail.setPrice(orderDetail.getPrice()); -// insertDetail.setNumber(orderDetail.getNumber()); -// insertDetail.setSubtotal(orderDetail.getSubtotal()); -// if(orderDetail.getIsUsedCoupons() != null){ -// insertDetail.setIsUsedCoupons(orderDetail.getIsUsedCoupons()); -// insertDetail.setCouponsDiscountPrice(orderDetail.getCouponsDiscountPrice()); -// insertDetail.setAfterCouponsDiscountPrice(orderDetail.getPrice().subtract(orderDetail.getCouponsDiscountPrice())); -// } -// insertDetail.setIsDeleted(false); -// orderDetailService.insertSelective(insertDetail); -// -// //TODO - 减少商品库存 (规格的库存该怎么去变化) -// /*goodsFeignApi.decreaseStock(goodsId, number);*/ -// } -// -//// //4、如果是从购物车下单的 那么下单成功后需要删除购物车数据 注意用批量删除 -//// if(param.getShoppingCartIdList()!=null && param.getShoppingCartIdList().size()>0){ -//// shoppingCartFeignApi.batchDeleteByIdList(param.getShoppingCartIdList()); -//// } -// -// //5、修改是否为新用户标识 -// if(dbMember.getIsNewPeople()){ -// dbMember.setIsNewPeople(false); -// dbMember.setIsRemindNewPeople(false); -// memberFeignApi.updateByPrimaryKeySelective(dbMember); -// } -// -// //模拟程序出错 -//// int i = 10 / 0; -// -// //6、更新优惠卷的使用状态 -// if (param.getCouponsMemberRelationId() != null) { -// couponsMemberRelationFeignApi.updateCouponsUsed(param.getCouponsMemberRelationId(),true); -// } -// -// //加入MQ延时队列,检测并关闭超时未支付的订单,5分钟 -// Message message = new Message("TID_COMMON_MALL", "CLOSE_OVERDUE_ORDER", JSON.toJSONString(dbOrder).getBytes()); -// message.setDelayTimeLevel(RocketMQConst.DELAY_TIME_LEVEL_5M); -// RocketMQTemplate rocketMQTemplate = applicationContext.getBean("rocketMQTemplate", RocketMQTemplate.class); -// rocketMQTemplate.getProducer().send(message); -// -// //插入事务日志 -// TransactionLog transactionLog = new TransactionLog(); -// transactionLog.setId(transId); -// transactionLog.setBusiness("order"); -// transactionLog.setForeignKey(String.valueOf(dbOrder.getId())); -// transactionLogService.insert(transactionLog); -// -// return dbOrder; - - return null; - } - - @Override - public void cancelOrderByUnPaid(OrderParam param) { - - } - - @Override - public void cancelOrderNoReason(OrderParam param) throws IOException { - - } - - @Override - public void applyRefund(OrderParam param) throws IOException { - - } - - @Override - public void confirmReceipt(OrderParam param) { - - } - - @Override - public Order selectByPrimaryKey(Integer id) { - return null; - } - - @Override - public void updateByPrimaryKeySelective(Order record) { - - } - - @Override - public Page getListByPageWithAsc(OrderParam param) { - return null; - } - - @Override - public Page> getListByPageWithDesc(OrderParam param) { - return null; - } - - @Override - public Order selectByOrderNo(String orderNo) { - return null; - } - - @Override - public void closeOverdueOrder(Integer id) { - - } - - @Override - public void autoCompletedOrder(Integer id) { - - } - - @Override - public void printRceceipts(Integer id) { - - } - - @Override - public int batchUpdateIsPrintedTrue(List idList) { - return 0; - } - - @Override - public Integer getNextQueueNo() { - return null; - } - - @Override - public Page getListByTodayOrderWithAsc(OrderParam param) { - return null; - } - - @Override - public void paymentNotify(String outTradeNo) throws IOException, InterruptedException, RemotingException, MQClientException, MQBrokerException { - - } - - @Override - public void paymentNotifyOfChangeToDelivery(String changeToDeliveryOutTradeNo) { - - } - - @Override - public Map countOrder(OrderParam order) { - return null; - } - - @Override - public int selectLatelyMonthlySalesByShopId(Date startTime, Date endTime, Integer shopId) { - return 0; - } - - @Override - public BigDecimal selectSumMerchantIncome(OrderParam param) { - return null; - } - - @Override - public BigDecimal selectSumActualPrice(OrderParam param) { - return null; - } - - @Override - public int selectCountCompleted(OrderParam param) { - return 0; - } - - @Override - public int selectCountPaid(OrderParam param) { - return 0; - } - - @Override - public boolean getIsAllowCancelNoReason(OrderParam order) { - return false; - } - - @Override - public boolean getIsAllowApplyRefund(OrderParam order) { - return false; - } - - @Override - public Page getAfterSalesListByPageWithAsc(OrderParam param) { - return null; - } - - @Override - public void updatePayOrderFrozenBalanceOfMerchant() { - - } - - @Override - public void remindOvertimeOrder(Integer id) throws IOException { - - } - - @Override - public List> selectStatisticOrder(Integer shopId) { - return null; - } - - @Override - public String selectStartDateOrder(Integer shopId) { - return null; - } - - @Override - public int selectCountPayers(OrderParam param) { - return 0; - } - - @Override - public int selectCountOrderPeoples(OrderParam param) { - return 0; - } - - @Override - public void refundMerchantBalance(String out_trade_no) { - - } - - @Override - public Map selectSumField(OrderParam order) { - return null; - } - - @Override - public int selectCountUnCompleted(OrderParam order) { - return 0; - } - - @Override - public int selectCountWaitHandle(OrderParam order) { - return 0; - } - - @Override - public OrderVo selectById(OrderParam param) { - return null; - } - - @Override - public OrderVo2 selectRefundProcess(OrderParam param) { - return null; - } - - @Override - public Map selectTabNumber(OrderParam param) { - return null; - } - - @Override - public void batchUpdateIsPrintedTrue(OrderParam param) { - - } - - @Override - public Map selectAllTabWaitHandleNum(OrderParam param) { - return null; - } - - @Override - public List waitPrintOrderList(OrderParam param) { - return null; - } - - @Override - public void auditAfterSalesOrderByAdmin(OrderParam param) { - - } - - @Override - public void auditAfterSalesOrderByMerchant(OrderParam param) { - - } - - @Override - public Map statistic(OrderParam param) throws ParseException { - return null; - } - - @Override - public void printOrderReceipt(Order dbOrder, String printType) { - - } - - @Override - public void allocatingFunds(Order dbOrder) { - - } - - @Override - public boolean save(Order entity) { - return false; - } - - @Override - public boolean saveBatch(Collection entityList, int batchSize) { - return false; - } - - @Override - public boolean saveOrUpdateBatch(Collection entityList, int batchSize) { - return false; - } - - @Override - public boolean removeById(Serializable id) { - return false; - } - - @Override - public boolean removeByMap(Map columnMap) { - return false; - } - - @Override - public boolean remove(Wrapper queryWrapper) { - return false; - } - - @Override - public boolean removeByIds(Collection idList) { - return false; - } - - @Override - public boolean updateById(Order entity) { - return false; - } - - @Override - public boolean update(Order entity, Wrapper updateWrapper) { - return false; - } - - @Override - public boolean updateBatchById(Collection entityList, int batchSize) { - return false; - } - - @Override - public boolean saveOrUpdate(Order entity) { - return false; - } - - @Override - public Order getById(Serializable id) { - return null; - } - - @Override - public List listByIds(Collection idList) { - return null; - } - - @Override - public List listByMap(Map columnMap) { - return null; - } - - @Override - public Order getOne(Wrapper queryWrapper, boolean throwEx) { - return null; - } - - @Override - public Map getMap(Wrapper queryWrapper) { - return null; - } - - @Override - public V getObj(Wrapper queryWrapper, Function mapper) { - return null; - } - - @Override - public int count(Wrapper queryWrapper) { - return 0; - } - - @Override - public List list(Wrapper queryWrapper) { - return null; - } - - @Override - public > E page(E page, Wrapper queryWrapper) { - return null; - } - - @Override - public List> listMaps(Wrapper queryWrapper) { - return null; - } - - @Override - public List listObjs(Wrapper queryWrapper, Function mapper) { - return null; - } - - @Override - public >> E pageMaps(E page, Wrapper queryWrapper) { - return null; - } - - @Override - public BaseMapper getBaseMapper() { - return null; - } -} \ No newline at end of file diff --git a/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/internal/distributed_transaction/Seata_OrderServiceImpl.java b/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/internal/distributed_transaction/Seata_OrderServiceImpl.java deleted file mode 100644 index 992a2fb..0000000 --- a/siam-order/order-provider/src/main/java/com/siam/package_order/service_impl/internal/distributed_transaction/Seata_OrderServiceImpl.java +++ /dev/null @@ -1,692 +0,0 @@ -package com.siam.package_order.service_impl.internal.distributed_transaction; - -import com.baomidou.mybatisplus.core.conditions.Wrapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.siam.package_common.util.RedisUtils; -import com.siam.package_goods.feign.GoodsFeignApi; -import com.siam.package_goods.feign.GoodsSpecificationOptionFeignApi; -import com.siam.package_goods.feign.ShoppingCartFeignApi; -import com.siam.package_order.controller.member.WxPayService; -import com.siam.package_order.entity.Order; -import com.siam.package_order.mapper.OrderMapper; -import com.siam.package_order.model.example.OrderExample; -import com.siam.package_order.model.param.OrderParam; -import com.siam.package_order.model.vo.OrderVo; -import com.siam.package_order.model.vo.OrderVo2; -import com.siam.package_order.service.*; -import com.siam.package_promotion.feign.CouponsFeignApi; -import com.siam.package_promotion.feign.CouponsGoodsRelationFeignApi; -import com.siam.package_promotion.feign.CouponsMemberRelationFeignApi; -import com.siam.package_promotion.feign.FullReductionRuleFeignApi; -import com.siam.package_user.auth.cache.MemberSessionManager; -import com.siam.package_user.feign.*; -import com.siam.package_user.feign.internal.VipRechargeRecordFeignApi; -import com.siam.package_util.feign.SettingFeignApi; -import com.siam.package_weixin_basic.service.WxNotifyService; -import com.siam.package_weixin_basic.service.WxPublicPlatformNotifyService; -import io.seata.spring.annotation.GlobalTransactional; -import lombok.extern.slf4j.Slf4j; -import org.apache.rocketmq.client.exception.MQBrokerException; -import org.apache.rocketmq.client.exception.MQClientException; -import org.apache.rocketmq.remoting.exception.RemotingException; -import org.apache.rocketmq.spring.core.RocketMQTemplate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; - -import javax.annotation.Resource; -import java.io.IOException; -import java.io.Serializable; -import java.math.BigDecimal; -import java.text.ParseException; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -/** - * 分布式事务-seata - * - * @return - * @author 暹罗 - */ -@Slf4j -@Service -public class Seata_OrderServiceImpl implements OrderService { - - public static final String USER_ORDER_TOKEN_PREFIX = "order:token:"; - - @Autowired - private OrderMapper orderMapper; - - @Autowired - private OrderDetailService orderDetailService; - - @Autowired - private SettingFeignApi settingFeignApi; - - @Autowired - private MemberBillingRecordFeignApi memberBillingRecordFeignApi; - - @Autowired - private MemberFeignApi memberFeignApi; - - @Autowired - private MemberTradeRecordFeignApi memberTradeRecordFeignApi; - - @Autowired - private DeliveryAddressFeignApi deliveryAddressFeignApi; - - @Autowired - private WxNotifyService wxNotifyService; - - @Autowired - private WxPublicPlatformNotifyService wxPublicPlatformNotifyService; - - @Autowired - private OrderRefundService orderRefundService; - - @Autowired - private MemberInviteRelationFeignApi memberInviteRelationFeignApi; - - @Resource(name = "orderServiceImpl") - private OrderService orderService; - - @Autowired - private VipRechargeRecordFeignApi vipRechargeRecordFeignApi; - - @Autowired - private OrderRefundGoodsService orderRefundGoodsService; - - @Autowired - private OrderRefundProcessService orderRefundProcessService; - - @Autowired - private WxPayService wxPayService; - - @Autowired - private MemberSessionManager memberSessionManager; - - @Autowired - private CommonService commonService; - - @Autowired - private ShoppingCartFeignApi shoppingCartFeignApi; - - @Autowired - private GoodsFeignApi goodsFeignApi; - - @Autowired - private GoodsSpecificationOptionFeignApi goodsSpecificationOptionFeignApi; - - @Autowired - private CouponsMemberRelationFeignApi couponsMemberRelationFeignApi; - - @Autowired - private CouponsFeignApi couponsFeignApi; - - @Autowired - private CouponsGoodsRelationFeignApi couponsGoodsRelationFeignApi; - - @Autowired - private FullReductionRuleFeignApi fullReductionRuleFeignApi; - - @Autowired - private ApplicationContext applicationContext; - - @Autowired - private RedisUtils redisUtils; - - @Autowired - private RedisTemplate redisTemplate; - - @Override - public void delete(OrderParam param) { - - } - - @Override - @GlobalTransactional(timeoutMills = 60000, name = "spring-cloud-seata", rollbackFor = Exception.class) - public Order insert(OrderParam param) { -// //TODO(MARK) - 购物车下单、直接购买两种形式可以不拆分成两个接口 -// //TODO(MARK) - 系统默认免运费 -// param.setDeliveryFee(BigDecimal.ZERO); -// -// log.info("开始全局事务,XID = " + RootContext.getXID()); -// -//// Member loginMember = memberSessionManager.getSession(TokenUtil.getToken()); -//// Member dbMember = memberFeignApi.selectByPrimaryKey(loginMember.getId()); -// -// Member dbMember = memberFeignApi.selectByPrimaryKey(2).getData(); -// -// -//// //校验防重令牌是否正确 -- 保证该接口的幂等性 -//// String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; -//// Long result = (Long) redisTemplate.execute(new DefaultRedisScript(script, Long.class), Arrays.asList(USER_ORDER_TOKEN_PREFIX + loginMember.getId()), param.getOrderToken()); -//// if(result == 0){ -//// throw new StoneCustomerException("请勿重复提交"); -//// } -// -// //校验:如果是从购物车下单的 那么需要校验购物车数据是否存在 以及购物车数据是否属于当前登录用户 -// if(param.getShoppingCartIdList()!=null && !param.getShoppingCartIdList().isEmpty()){ -// int count = shoppingCartFeignApi.countByIdListAndMemberId(param.getShoppingCartIdList(), dbMember.getId()).getData(); -// if(count != param.getShoppingCartIdList().size()){ -// throw new StoneCustomerException("购物车数据异常,请刷新页面重新下单"); -// } -// } -// -// //根据收货地址id回写联系人信息 -// DeliveryAddress dbDeliveryAddress = deliveryAddressFeignApi.selectByPrimaryKey(param.getDeliveryAddressId()); -// if(dbDeliveryAddress == null){ -// throw new StoneCustomerException("该收货地址不存在"); -// } -// param.setContactRealname(dbDeliveryAddress.getRealname()); -// param.setContactPhone(dbDeliveryAddress.getPhone()); -// param.setContactProvince(dbDeliveryAddress.getProvince()); -// param.setContactCity(dbDeliveryAddress.getCity()); -// param.setContactArea(dbDeliveryAddress.getArea()); -// param.setContactStreet(dbDeliveryAddress.getStreet()); -// param.setContactSex(dbDeliveryAddress.getSex()); -// param.setContactHouseNumber(dbDeliveryAddress.getHouseNumber()); -// param.setContactLongitude(dbDeliveryAddress.getLongitude()); -// param.setContactLatitude(dbDeliveryAddress.getLatitude()); -// -// //1、校验前端的实付款金额是否正确 -// this.validatePrice(param); -// -// //生成订单编号 -// String orderNo = GenerateNo.getOrderNo(); -// //生成订单取餐号 -// Integer queueNo = getNextQueueNo(); -// //生成支付截止时间(五分钟内未付款的订单会被自动关闭) -// Date paymentDeadline = DateUtilsPlus.addMinutes(new Date(), Quantity.INT_5); -// -// //2、添加订单记录 -// Order insertOrder = new Order(); -// insertOrder.setMemberId(dbMember.getId()); -// insertOrder.setOrderNo(orderNo); -// insertOrder.setGoodsTotalQuantity(param.getGoodsTotalQuantity()); -// insertOrder.setGoodsTotalPrice(param.getGoodsTotalPrice()); -// insertOrder.setDeliveryFee(param.getDeliveryFee()); -// insertOrder.setActualPrice(param.getActualPrice()); -// insertOrder.setShoppingWay(Quantity.INT_2); -// insertOrder.setDeliveryAddressId(param.getDeliveryAddressId()); -// insertOrder.setContactRealname(param.getContactRealname()); -// insertOrder.setContactPhone(param.getContactPhone()); -// insertOrder.setContactProvince(param.getContactProvince()); -// insertOrder.setContactCity(param.getContactCity()); -// insertOrder.setContactArea(param.getContactArea()); -// insertOrder.setContactStreet(param.getContactStreet()); -// insertOrder.setContactSex(param.getContactSex()); -// insertOrder.setTradeId(null); -// insertOrder.setRemark(param.getRemark()); -// insertOrder.setDescription(param.getDescription()); -// insertOrder.setStatus(Quantity.INT_1); -// insertOrder.setOrderLogisticsId(null); -// insertOrder.setIsInvoice(false); -// insertOrder.setInvoiceId(null); -// insertOrder.setIsDeleted(false); -// insertOrder.setShopName(param.getShopName()); -// insertOrder.setShopAddress(param.getShopAddress()); -// insertOrder.setCancelReason(null); -// insertOrder.setPaymentDeadline(paymentDeadline); -// insertOrder.setCreateTime(new Date()); -// insertOrder.setUpdateTime(new Date()); -// insertOrder.setQueueNo(queueNo); -// insertOrder.setFullReductionRuleId(param.getFullReductionRuleId()); -// insertOrder.setFullReductionRuleDescription(param.getFullReductionRuleDescription()); -// insertOrder.setCouponsId(param.getCouponsId()); -// insertOrder.setCouponsMemberRelationId(param.getCouponsMemberRelationId()); -// insertOrder.setCouponsDescription(param.getCouponsDescription()); -// insertOrder.setLimitedPrice(param.getLimitedPrice()); -// insertOrder.setReducedPrice(param.getReducedPrice()); -// insertOrder.setCouponsDiscountPrice(param.getCouponsDiscountPrice()); -// insertOrder.setDeliveryWay(param.getDeliveryWay()); -// insertOrder.setIsPayToMerchant(false); -// insertOrder.setBeforeReducedDeliveryFee(param.getBeforeReducedDeliveryFee()); -// insertOrder.setContactHouseNumber(param.getContactHouseNumber()); -// insertOrder.setContactLongitude(param.getContactLongitude()); -// insertOrder.setContactLatitude(param.getContactLatitude()); -// insertOrder.setFirstGoodsMainImage(param.getFirstGoodsMainImage()); -// orderMapper.insert(insertOrder); -// -// //获取最新订单对象 -// Order dbOrder = orderMapper.selectById(insertOrder.getId()); -// -// //3、添加订单商品详情记录 -// for(OrderDetail orderDetail : param.getOrderDetailList()){ -// // 添加订单商品详情记录 -// OrderDetail insertDetail = new OrderDetail(); -// insertDetail.setOrderId(dbOrder.getId()); -// insertDetail.setGoodsId(orderDetail.getGoodsId()); -// insertDetail.setGoodsName(orderDetail.getGoodsName()); -// insertDetail.setMainImage(orderDetail.getMainImage()); -// insertDetail.setSpecList(orderDetail.getSpecList()); -// insertDetail.setPrice(orderDetail.getPrice()); -// insertDetail.setNumber(orderDetail.getNumber()); -// insertDetail.setSubtotal(orderDetail.getSubtotal()); -// if(orderDetail.getIsUsedCoupons() != null){ -// insertDetail.setIsUsedCoupons(orderDetail.getIsUsedCoupons()); -// insertDetail.setCouponsDiscountPrice(orderDetail.getCouponsDiscountPrice()); -// insertDetail.setAfterCouponsDiscountPrice(orderDetail.getPrice().subtract(orderDetail.getCouponsDiscountPrice())); -// } -// insertDetail.setIsDeleted(false); -// orderDetailService.insertSelective(insertDetail); -// -// //TODO - 减少商品库存 (规格的库存该怎么去变化) -// /*goodsFeignApi.decreaseStock(goodsId, number);*/ -// } -// -// //4、如果是从购物车下单的 那么下单成功后需要删除购物车数据 注意用批量删除 -// if(param.getShoppingCartIdList()!=null && param.getShoppingCartIdList().size()>0){ -// BasicResult basicResult = shoppingCartFeignApi.batchDeleteByIdList(param.getShoppingCartIdList()); -// if(!basicResult.getSuccess()){ -// try { -// GlobalTransactionContext.reload(RootContext.getXID()).rollback(); -// throw new StoneCustomerException("下单失败,请稍后重试"); -// } catch (TransactionException e) { -// e.printStackTrace(); -// } -// } -// } -// -// //5、修改是否为新用户标识 -// if(dbMember.getIsNewPeople()){ -// dbMember.setIsNewPeople(false); -// dbMember.setIsRemindNewPeople(false); -// BasicResult basicResult = memberFeignApi.updateByPrimaryKeySelective(dbMember); -// if(!basicResult.getSuccess()){ -// try { -// GlobalTransactionContext.reload(RootContext.getXID()).rollback(); -// throw new StoneCustomerException("下单失败,请稍后重试"); -// } catch (TransactionException e) { -// e.printStackTrace(); -// } -// } -// } -// -//// //模拟程序出错 -//// int i = 10 / 0; -// -// //6、更新优惠卷的使用状态 -// if (param.getCouponsMemberRelationId() != null) { -// couponsMemberRelationFeignApi.updateCouponsUsed(param.getCouponsMemberRelationId(),true); -// } -// -// //加入MQ延时队列,检测并关闭超时未支付的订单,5分钟 -// Message message = new Message("TID_COMMON_MALL", "CLOSE_OVERDUE_ORDER", JSON.toJSONString(dbOrder).getBytes()); -// message.setDelayTimeLevel(RocketMQConst.DELAY_TIME_LEVEL_5M); -// RocketMQTemplate rocketMQTemplate = applicationContext.getBean("rocketMQTemplate", RocketMQTemplate.class); -// rocketMQTemplate.getProducer().send(message); -// -// return dbOrder; - - return null; - } - - @Override - public Order insertByMQ(OrderParam param, String transId) throws InterruptedException, RemotingException, MQClientException, MQBrokerException { - return null; - } - - @Override - public void cancelOrderByUnPaid(OrderParam param) { - - } - - @Override - public void cancelOrderNoReason(OrderParam param) throws IOException { - - } - - @Override - public void applyRefund(OrderParam param) throws IOException { - - } - - @Override - public void confirmReceipt(OrderParam param) { - - } - - - @Override - public Order selectByPrimaryKey(Integer id) { - return null; - } - - - @Override - public void updateByPrimaryKeySelective(Order record) { - - } - - @Override - public Page getListByPageWithAsc(OrderParam param) { - return null; - } - - @Override - public Page> getListByPageWithDesc(OrderParam param) { - return null; - } - - @Override - public Order selectByOrderNo(String orderNo) { - return null; - } - - @Override - public void closeOverdueOrder(Integer id) { - - } - - @Override - public void autoCompletedOrder(Integer id) { - - } - - @Override - public void printRceceipts(Integer id) { - - } - - @Override - public int batchUpdateIsPrintedTrue(List idList) { - return 0; - } - - @Override - public Integer getNextQueueNo() { - return null; - } - - @Override - public Page getListByTodayOrderWithAsc(OrderParam param) { - return null; - } - - @Override - public void paymentNotify(String outTradeNo) throws IOException, InterruptedException, RemotingException, MQClientException, MQBrokerException { - - } - - @Override - public void paymentNotifyOfChangeToDelivery(String changeToDeliveryOutTradeNo) { - - } - - @Override - public Map countOrder(OrderParam order) { - return null; - } - - @Override - public int selectLatelyMonthlySalesByShopId(Date startTime, Date endTime, Integer shopId) { - return 0; - } - - @Override - public BigDecimal selectSumMerchantIncome(OrderParam param) { - return null; - } - - @Override - public BigDecimal selectSumActualPrice(OrderParam param) { - return null; - } - - @Override - public int selectCountCompleted(OrderParam param) { - return 0; - } - - @Override - public int selectCountPaid(OrderParam param) { - return 0; - } - - @Override - public boolean getIsAllowCancelNoReason(OrderParam order) { - return false; - } - - @Override - public boolean getIsAllowApplyRefund(OrderParam order) { - return false; - } - - @Override - public Page getAfterSalesListByPageWithAsc(OrderParam param) { - return null; - } - - @Override - public void updatePayOrderFrozenBalanceOfMerchant() { - - } - - @Override - public void remindOvertimeOrder(Integer id) throws IOException { - - } - - @Override - public List> selectStatisticOrder(Integer shopId) { - return null; - } - - @Override - public String selectStartDateOrder(Integer shopId) { - return null; - } - - @Override - public int selectCountPayers(OrderParam param) { - return 0; - } - - @Override - public int selectCountOrderPeoples(OrderParam param) { - return 0; - } - - @Override - public void refundMerchantBalance(String out_trade_no) { - - } - - @Override - public Map selectSumField(OrderParam order) { - return null; - } - - @Override - public int selectCountUnCompleted(OrderParam order) { - return 0; - } - - @Override - public int selectCountWaitHandle(OrderParam order) { - return 0; - } - - @Override - public OrderVo selectById(OrderParam param) { - return null; - } - - @Override - public OrderVo2 selectRefundProcess(OrderParam param) { - return null; - } - - @Override - public Map selectTabNumber(OrderParam param) { - return null; - } - - @Override - public void batchUpdateIsPrintedTrue(OrderParam param) { - - } - - @Override - public Map selectAllTabWaitHandleNum(OrderParam param) { - return null; - } - - @Override - public List waitPrintOrderList(OrderParam param) { - return null; - } - - @Override - public void auditAfterSalesOrderByAdmin(OrderParam param) { - - } - - @Override - public void auditAfterSalesOrderByMerchant(OrderParam param) { - - } - - @Override - public Map statistic(OrderParam param) throws ParseException { - return null; - } - - @Override - public void printOrderReceipt(Order dbOrder, String printType) { - - } - - @Override - public void allocatingFunds(Order dbOrder) { - - } - - @Override - public boolean save(Order entity) { - return false; - } - - @Override - public boolean saveBatch(Collection entityList, int batchSize) { - return false; - } - - @Override - public boolean saveOrUpdateBatch(Collection entityList, int batchSize) { - return false; - } - - @Override - public boolean removeById(Serializable id) { - return false; - } - - @Override - public boolean removeByMap(Map columnMap) { - return false; - } - - @Override - public boolean remove(Wrapper queryWrapper) { - return false; - } - - @Override - public boolean removeByIds(Collection idList) { - return false; - } - - @Override - public boolean updateById(Order entity) { - return false; - } - - @Override - public boolean update(Order entity, Wrapper updateWrapper) { - return false; - } - - @Override - public boolean updateBatchById(Collection entityList, int batchSize) { - return false; - } - - @Override - public boolean saveOrUpdate(Order entity) { - return false; - } - - @Override - public Order getById(Serializable id) { - return null; - } - - @Override - public List listByIds(Collection idList) { - return null; - } - - @Override - public List listByMap(Map columnMap) { - return null; - } - - @Override - public Order getOne(Wrapper queryWrapper, boolean throwEx) { - return null; - } - - @Override - public Map getMap(Wrapper queryWrapper) { - return null; - } - - @Override - public V getObj(Wrapper queryWrapper, Function mapper) { - return null; - } - - @Override - public int count(Wrapper queryWrapper) { - return 0; - } - - @Override - public List list(Wrapper queryWrapper) { - return null; - } - - @Override - public > E page(E page, Wrapper queryWrapper) { - return null; - } - - @Override - public List> listMaps(Wrapper queryWrapper) { - return null; - } - - @Override - public List listObjs(Wrapper queryWrapper, Function mapper) { - return null; - } - - @Override - public >> E pageMaps(E page, Wrapper queryWrapper) { - return null; - } - - @Override - public BaseMapper getBaseMapper() { - return null; - } -} \ No newline at end of file diff --git a/siam-order/order-provider/src/main/resources/application-local.yml b/siam-order/order-provider/src/main/resources/application-local.yml index c49f3c0..88c903b 100644 --- a/siam-order/order-provider/src/main/resources/application-local.yml +++ b/siam-order/order-provider/src/main/resources/application-local.yml @@ -5,9 +5,9 @@ server: spring: #mysql datasource: - url: jdbc:mysql://127.0.0.1:3306/siam_cloud?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8 + url: jdbc:mysql://127.0.0.1:3306/siam_cloud?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true username: root - password: root + password: 123456 #thymeleaf thymeleaf: @@ -61,6 +61,18 @@ spring: application: name: order-siam + # Nacos注册中心/配置中心 + cloud: + nacos: + discovery: + server-addr: 127.0.0.1:8848 + config: + server-addr: 127.0.0.1:8848 + file-extension: yaml + config: + import: + - optional:nacos:${spring.application.name}-local.yaml + #配置文件上传大小限制 servlet: multipart: @@ -91,15 +103,15 @@ spring: ds0: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver - url: jdbc:mysql://127.0.0.1:3306/siam_cloud_0?characterEncoding=utf-8&useUnicode=true&useSSL=true + url: jdbc:mysql://127.0.0.1:3306/siam_cloud_0?characterEncoding=utf-8&useUnicode=true&useSSL=true&allowPublicKeyRetrieval=true username: root - password: root + password: 123456 ds1: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver - url: jdbc:mysql://127.0.0.1:3306/siam_cloud_1?characterEncoding=utf-8&useUnicode=true&useSSL=true + url: jdbc:mysql://127.0.0.1:3306/siam_cloud_1?characterEncoding=utf-8&useUnicode=true&useSSL=true&allowPublicKeyRetrieval=true username: root - password: root + password: 123456 props: sql: show: true #是否显示sharding-jdbc的sql路由 @@ -179,17 +191,7 @@ mybatis-plus: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl -#eureka配置 -eureka: - client: - service-url: - defaultZone: http://127.0.0.1:9000/eureka/ - register-with-eureka: true - fetch-registry: true - instance: - #配置使用ip地址来注册(默认是主机名称) - prefer-ip-address: true - #心跳检测暂时不配置 +# Nacos注册中心/配置中心 feign: #feign内部服务调用超时配置-第二种 @@ -222,24 +224,31 @@ rocketmq: # Seata Config seata: - application-id: order-service + application-id: ${spring.application.name} tx-service-group: my_test_tx_group service: vgroup-mapping: - # 此处配置对应Server端配置registry.eureka.application的值 my_test_tx_group: default registry: - type: eureka - eureka: - service-url: http://127.0.0.1:9000/eureka/ - weight: 1 + type: nacos + nacos: + application: seata-server + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public + config: + type: nacos + nacos: + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public #springboot admin相关配置 management: endpoints: web: exposure: - include: "*" #'prometheus,health' + include: "health,prometheus,info" exclude: "shutdown" base-path: /actuator endpoint: @@ -264,6 +273,8 @@ management: enabled: false elasticsearch: enabled: false + mail: # 加上这一行 + enabled: false # 加上这一行,关闭邮件自检 #日志配置 logging: diff --git a/siam-order/order-provider/src/test/java/com/siam/package_order/OrderApplicationTest.java b/siam-order/order-provider/src/test/java/com/siam/package_order/OrderApplicationTest.java index 59bf625..ad32fa3 100644 --- a/siam-order/order-provider/src/test/java/com/siam/package_order/OrderApplicationTest.java +++ b/siam-order/order-provider/src/test/java/com/siam/package_order/OrderApplicationTest.java @@ -32,7 +32,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.test.context.junit4.SpringRunner; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import java.io.IOException; import java.util.List; import java.util.Map; diff --git a/siam-order/order-provider/src/test/java/com/siam/package_order/internal/DistributedTransactionTest.java b/siam-order/order-provider/src/test/java/com/siam/package_order/internal/DistributedTransactionTest.java index 604d7d7..a3ba0eb 100644 --- a/siam-order/order-provider/src/test/java/com/siam/package_order/internal/DistributedTransactionTest.java +++ b/siam-order/order-provider/src/test/java/com/siam/package_order/internal/DistributedTransactionTest.java @@ -15,7 +15,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; -import javax.annotation.Resource; +import jakarta.annotation.Resource; /** * 分布式事务相关 diff --git a/siam-order/pom.xml b/siam-order/pom.xml index 47ad03c..32e5a78 100644 --- a/siam-order/pom.xml +++ b/siam-order/pom.xml @@ -31,8 +31,6 @@ UTF-8 - 1.8 - 1.8 \ No newline at end of file diff --git a/siam-parent/pom.xml b/siam-parent/pom.xml index fb4b552..90aea03 100644 --- a/siam-parent/pom.xml +++ b/siam-parent/pom.xml @@ -20,83 +20,138 @@ ../siam-mall ../siam-util ../siam-monitor - ../siam-eureka - ../siam-zuul + ../siam-gateway siam-parent - https://www.siamit.cn UTF-8 - 1.8 - 1.8 + 17 + 17 + 17 + + + 2023.0.1 + 2023.0.1.0 + 3.5.5 + 3.0.4 + 1.18.30 + 2.5.0 + 7.4 - + org.springframework.boot spring-boot-dependencies - 2.3.3.RELEASE + 3.2.5 pom import - - + org.springframework.cloud spring-cloud-dependencies - Finchley.M7 + ${spring-cloud.version} + pom + import + + + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring-cloud-alibaba.version} pom import - --> + + + + + mysql + mysql-connector-java + 8.0.33 + + + + + org.mybatis + mybatis-spring + ${mybatis-spring.version} + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + ${springdoc.version} + + + + + net.logstash.logback + logstash-logback-encoder + ${logstash-logback.version} + + + + + de.codecentric + spring-boot-admin-starter-client + 3.2.3 + + + de.codecentric + spring-boot-admin-starter-server + 3.2.3 + + + + + org.springframework.boot + spring-boot-maven-plugin + 3.2.5 + + + - - - - org.apache.maven.plugins maven-surefire-plugin - 2.18.1 + 3.2.5 true - org.apache.maven.plugins maven-compiler-plugin + 3.11.0 - 8 - 8 + 17 + 17 + + -parameters + - src/main/resources true - src/main/java @@ -147,4 +202,4 @@ - \ No newline at end of file + diff --git a/siam-promotion/pom.xml b/siam-promotion/pom.xml index 4a681e8..d713ed7 100644 --- a/siam-promotion/pom.xml +++ b/siam-promotion/pom.xml @@ -32,8 +32,6 @@ UTF-8 - 1.8 - 1.8 \ No newline at end of file diff --git a/siam-promotion/promotion-api/pom.xml b/siam-promotion/promotion-api/pom.xml index a004654..64f0840 100644 --- a/siam-promotion/promotion-api/pom.xml +++ b/siam-promotion/promotion-api/pom.xml @@ -16,8 +16,6 @@ UTF-8 - 1.8 - 1.8 @@ -25,7 +23,6 @@ org.springframework.boot spring-boot-starter-data-elasticsearch - 2.1.4.RELEASE @@ -37,7 +34,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 exec diff --git a/siam-promotion/promotion-api/src/main/java/com/siam/package_promotion/entity/Advertisement.java b/siam-promotion/promotion-api/src/main/java/com/siam/package_promotion/entity/Advertisement.java index d303e36..eaa6d07 100644 --- a/siam-promotion/promotion-api/src/main/java/com/siam/package_promotion/entity/Advertisement.java +++ b/siam-promotion/promotion-api/src/main/java/com/siam/package_promotion/entity/Advertisement.java @@ -3,42 +3,41 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.Date; @Data @TableName("tb_advertisement") -@ApiModel(value = "广告轮播图表") + @Schema(description= "广告轮播图表") public class Advertisement { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "轮播图名称") + @Schema(description = "轮播图名称") private String imageName; - @ApiModelProperty(notes = "轮播图路径") + @Schema(description = "轮播图路径") private String imagePath; - @ApiModelProperty(notes = "说明") + @Schema(description = "说明") private String description; - @ApiModelProperty(notes = "轮播图类型 1=首页轮播图 2=菜单页轮播图") + @Schema(description = "轮播图类型 1=首页轮播图 2=菜单页轮播图") private Integer type; - @ApiModelProperty(notes = "排序号") + @Schema(description = "排序号") private Integer sortNumber; - @ApiModelProperty(notes = "点击轮播图跳转的链接") + @Schema(description = "点击轮播图跳转的链接") private String imageLinkUrl; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; public Integer getId() { diff --git a/siam-promotion/promotion-api/src/main/java/com/siam/package_promotion/entity/Rawmaterial.java b/siam-promotion/promotion-api/src/main/java/com/siam/package_promotion/entity/Rawmaterial.java index 8309c60..4c9e4c7 100644 --- a/siam-promotion/promotion-api/src/main/java/com/siam/package_promotion/entity/Rawmaterial.java +++ b/siam-promotion/promotion-api/src/main/java/com/siam/package_promotion/entity/Rawmaterial.java @@ -3,8 +3,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; @@ -12,40 +11,40 @@ @Data @TableName("tb_rawmaterial") -@ApiModel(value = "原料表") + @Schema(description= "原料表") public class Rawmaterial { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "原料名称") + @Schema(description = "原料名称") private String name; - @ApiModelProperty(notes = "原料主图") + @Schema(description = "原料主图") private String mainImage; - @ApiModelProperty(notes = "原料描述") + @Schema(description = "原料描述") private String description; - @ApiModelProperty(notes = "采购单位") + @Schema(description = "采购单位") private String unit; - @ApiModelProperty(notes = "采购单价") + @Schema(description = "采购单价") private BigDecimal price; - @ApiModelProperty(notes = "库存") + @Schema(description = "库存") private BigDecimal stock; - @ApiModelProperty(notes = "库存过低线/库存下限") + @Schema(description = "库存过低线/库存下限") private BigDecimal stockLowerLimit; - @ApiModelProperty(notes = "库存超出线/库存上限") + @Schema(description = "库存超出线/库存上限") private BigDecimal stockUpperLimit; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; //页码 diff --git a/siam-promotion/promotion-api/src/main/java/com/siam/package_promotion/model/param/AdvertisementParam.java b/siam-promotion/promotion-api/src/main/java/com/siam/package_promotion/model/param/AdvertisementParam.java index 3de469a..6a9b220 100644 --- a/siam-promotion/promotion-api/src/main/java/com/siam/package_promotion/model/param/AdvertisementParam.java +++ b/siam-promotion/promotion-api/src/main/java/com/siam/package_promotion/model/param/AdvertisementParam.java @@ -1,13 +1,13 @@ package com.siam.package_promotion.model.param; import com.siam.package_promotion.entity.Advertisement; -import io.swagger.annotations.ApiModel; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.Date; @Data -@ApiModel(value = "广告轮播图表") + @Schema(description= "广告轮播图表") public class AdvertisementParam extends Advertisement { //开始日期 diff --git a/siam-promotion/promotion-api/src/main/java/com/siam/package_promotion/model/param/SearchParam.java b/siam-promotion/promotion-api/src/main/java/com/siam/package_promotion/model/param/SearchParam.java index 1c30454..9fbf94a 100644 --- a/siam-promotion/promotion-api/src/main/java/com/siam/package_promotion/model/param/SearchParam.java +++ b/siam-promotion/promotion-api/src/main/java/com/siam/package_promotion/model/param/SearchParam.java @@ -2,7 +2,7 @@ import lombok.Data; -import javax.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotBlank; @Data public class SearchParam { diff --git a/siam-promotion/promotion-provider/pom.xml b/siam-promotion/promotion-provider/pom.xml index 87ab5dc..2a86097 100644 --- a/siam-promotion/promotion-provider/pom.xml +++ b/siam-promotion/promotion-provider/pom.xml @@ -16,8 +16,6 @@ UTF-8 - 1.8 - 1.8 @@ -77,51 +75,40 @@ - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - 2.1.2.RELEASE - - - + com.alibaba.cloud - spring-cloud-starter-alibaba-seata - 2021.1 - - - io.seata - seata-spring-boot-starter - - + spring-cloud-starter-alibaba-nacos-discovery + - io.seata - seata-spring-boot-starter - 1.3.0 + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config org.springframework.boot spring-boot-starter-actuator - 2.3.3.RELEASE io.micrometer micrometer-registry-prometheus - 1.5.4 net.logstash.logback logstash-logback-encoder - 6.6 + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui @@ -132,7 +119,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 com.siam.package_promotion.PromotionApplication diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/PromotionApplication.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/PromotionApplication.java index a27de84..da881cb 100644 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/PromotionApplication.java +++ b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/PromotionApplication.java @@ -1,15 +1,19 @@ package com.siam.package_promotion; -import org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @EnableFeignClients("com.siam") -@EnableEurekaClient -@SpringBootApplication(scanBasePackages = "com.siam", exclude = {RocketMQAutoConfiguration.class}) +@EnableDiscoveryClient +@SpringBootApplication(scanBasePackages = "com.siam", exclude = { + MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class +}) @MapperScan(basePackages = {"com.siam.**.mapper"}) public class PromotionApplication { diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/config/MybatisPlusConfig.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/config/MybatisPlusConfig.java index 9cecb06..c6146aa 100644 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/config/MybatisPlusConfig.java +++ b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/config/MybatisPlusConfig.java @@ -1,6 +1,8 @@ package com.siam.package_promotion.config; -import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -19,8 +21,11 @@ public class MybatisPlusConfig { * 分页插件 */ @Bean - public PaginationInterceptor paginationInterceptor() { - return new PaginationInterceptor(); + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); + interceptor.addInnerInterceptor(paginationInnerInterceptor); + return interceptor; } } \ No newline at end of file diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/config/Swagger2Config.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/config/Swagger2Config.java deleted file mode 100644 index d9d3467..0000000 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/config/Swagger2Config.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.siam.package_promotion.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; - -@Configuration -@EnableSwagger2 -public class Swagger2Config { - - @Bean - public Docket createRestApi() { - return new Docket(DocumentationType.SWAGGER_2) - .apiInfo(apiInfo()) - .select() - .apis(RequestHandlerSelectors.basePackage("com.siam"))//扫描包路径 - .paths(PathSelectors.any()) - .build(); - } - - // 构建api文档的详细信息函数,注意这里的注解引用的是哪个 - private ApiInfo apiInfo() { - return new ApiInfoBuilder() - .title("暹罗外卖-促销服务接口文档")//页面标题 - .description("")//描述 - .version("1.0")//版本号 - .build(); - } -} \ No newline at end of file diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminAdvertisementController.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminAdvertisementController.java index b450b67..209a91c 100644 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminAdvertisementController.java +++ b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminAdvertisementController.java @@ -6,8 +6,9 @@ import com.siam.package_promotion.entity.Advertisement; import com.siam.package_promotion.model.param.AdvertisementParam; import com.siam.package_promotion.service.AdvertisementService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -16,20 +17,20 @@ @RestController @RequestMapping(value = "/rest/admin/advertisement") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台广告轮播图模块相关接口", description = "AdminAdvertisementController") +@Tag(name = "后台广告轮播图模块相关接口", description = "AdminAdvertisementController") public class AdminAdvertisementController { @Autowired private AdvertisementService advertisementService; - @ApiOperation(value = "广告轮播图列表") + @Operation(summary = "广告轮播图列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) AdvertisementParam param) { Page page = advertisementService.getListByPage(param); return BasicResult.success(page); } - @ApiOperation(value = "新增广告轮播图") + @Operation(summary = "新增广告轮播图") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) AdvertisementParam param) { advertisementService.insertSelective(param); @@ -38,7 +39,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) AdvertisementParam @AdminPermission - @ApiOperation(value = "修改广告轮播图") + @Operation(summary = "修改广告轮播图") @PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) AdvertisementParam param) { advertisementService.updateByPrimaryKeySelective(param); @@ -46,7 +47,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) AdvertisementParam } @AdminPermission - @ApiOperation(value = "删除广告轮播图") + @Operation(summary = "删除广告轮播图") @DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) AdvertisementParam param) { //删除广告轮播图 @@ -54,7 +55,7 @@ public BasicResult delete(@RequestBody @Validated(value = {}) AdvertisementParam return BasicResult.success(); } - @ApiOperation(value = "获取单个广告轮播图详情信息") + @Operation(summary = "获取单个广告轮播图详情信息") @PostMapping(value = "/getById") public BasicResult getById(@RequestBody @Validated(value = {}) AdvertisementParam param) { Advertisement advertisement = advertisementService.selectByPrimaryKey(param); diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminCouponsController.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminCouponsController.java index 6c81c01..43a1796 100644 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminCouponsController.java +++ b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminCouponsController.java @@ -13,8 +13,9 @@ import com.siam.package_promotion.entity.CouponsShopRelation; import com.siam.package_promotion.service.CouponsService; import com.siam.package_promotion.service.CouponsShopRelationService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -27,7 +28,7 @@ @RestController @RequestMapping(value = "/rest/admin/coupons") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台优惠卷接口", description = "AdminCouponsController") +@Tag(name = "后台优惠卷接口", description = "AdminCouponsController") public class AdminCouponsController { @Autowired @@ -39,7 +40,7 @@ public class AdminCouponsController { @Autowired private CouponsShopRelationService couponsShopRelationService; - @ApiOperation(value = "新增优惠卷") + @Operation(summary = "新增优惠卷") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) Coupons param) { BasicResult basicResult = new BasicResult(); @@ -63,7 +64,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) Coupons param) { } @AdminPermission - @ApiOperation(value = "修改优惠卷-TODO") + @Operation(summary = "修改优惠卷-TODO") @PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) Coupons param) { BasicResult basicResult = new BasicResult(); @@ -75,7 +76,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) Coupons param) { } @AdminPermission - @ApiOperation(value = "删除优惠卷") + @Operation(summary = "删除优惠卷") @DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) Coupons param) { BasicResult basicResult = new BasicResult(); @@ -85,7 +86,7 @@ public BasicResult delete(@RequestBody @Validated(value = {}) Coupons param) { return BasicResult.success(); } - @ApiOperation(value = "查看优惠卷详情(包含关联商品)") + @Operation(summary = "查看优惠卷详情(包含关联商品)") @PostMapping(value = "/selectById") public BasicResult selectById(@RequestBody @Validated(value = {}) Coupons param) { BasicData basicResult = new BasicData(); @@ -95,7 +96,7 @@ public BasicResult selectById(@RequestBody @Validated(value = {}) Coupons param) return BasicResult.success(map); } - @ApiOperation(value = "满优惠卷列表") + @Operation(summary = "满优惠卷列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) Coupons param) { BasicData basicResult = new BasicData(); @@ -107,7 +108,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) Coupons param) { return BasicResult.success(page); } - @ApiOperation(value = "优惠卷时间修改(延长)") + @Operation(summary = "优惠卷时间修改(延长)") @PostMapping(value = "/updateEndTime") public BasicResult updateEndTime(@RequestBody @Validated(value = {}) Coupons param) { BasicResult basicResult = new BasicResult(); diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminCouponsGoodsRelationController.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminCouponsGoodsRelationController.java index 5a12efa..283054e 100644 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminCouponsGoodsRelationController.java +++ b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminCouponsGoodsRelationController.java @@ -7,8 +7,9 @@ import com.siam.package_common.util.GsonUtils; import com.siam.package_promotion.entity.CouponsGoodsRelation; import com.siam.package_promotion.service.CouponsGoodsRelationService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -19,13 +20,13 @@ @RestController @RequestMapping(value = "/rest/admin/couponsGoodsRelation") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台优惠卷接口", description = "AdminCouponsController") +@Tag(name = "后台优惠卷接口", description = "AdminCouponsController") public class AdminCouponsGoodsRelationController { @Autowired private CouponsGoodsRelationService couponsGoodsRelationService; - @ApiOperation(value = "新增优惠卷商品关系") + @Operation(summary = "新增优惠卷商品关系") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) CouponsGoodsRelation param) { BasicResult basicResult = new BasicResult(); @@ -39,7 +40,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) CouponsGoodsRelati return basicResult; } - @ApiOperation(value = "优惠卷商品关系列表查询") + @Operation(summary = "优惠卷商品关系列表查询") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) CouponsGoodsRelation param) { BasicData basicResult = new BasicData(); diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminCouponsMemberRelationController.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminCouponsMemberRelationController.java index 7777363..c137fa7 100644 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminCouponsMemberRelationController.java +++ b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminCouponsMemberRelationController.java @@ -11,8 +11,9 @@ import com.siam.package_promotion.service.CouponsService; import com.siam.package_user.entity.Member; import com.siam.package_user.feign.MemberFeignApi; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -28,7 +29,7 @@ @RestController @RequestMapping(value = "/rest/admin/couponsMemberRelation") @Transactional(rollbackFor = Exception.class) -@Api(tags = "管理端优惠卷用关系接口", description = "AdminCouponsMemberRelationController") +@Tag(name = "管理端优惠卷用关系接口", description = "AdminCouponsMemberRelationController") public class AdminCouponsMemberRelationController { @Autowired @@ -44,7 +45,7 @@ public class AdminCouponsMemberRelationController { private AliyunSms aliyunSms; - @ApiOperation(value = "赠送优惠卷") + @Operation(summary = "赠送优惠卷") @PostMapping(value = "/giveCoupons") public BasicResult giveCoupons(@RequestBody @Validated(value = {}) CouponsMemberRelation param) { BasicResult basicResult = new BasicResult(); @@ -97,7 +98,7 @@ public BasicResult giveCoupons(@RequestBody @Validated(value = {}) CouponsMember return BasicResult.success(); } - @ApiOperation(value = "赠送优惠卷(单发)") + @Operation(summary = "赠送优惠卷(单发)") @PostMapping(value = "/giveSingleCoupons") public BasicResult giveSingleCoupons(@RequestBody @Validated(value = {}) CouponsMemberRelation param) { BasicResult basicResult = new BasicResult(); diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminCouponsShopRelationController.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminCouponsShopRelationController.java index 9416539..55151d7 100644 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminCouponsShopRelationController.java +++ b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminCouponsShopRelationController.java @@ -5,8 +5,9 @@ import com.siam.package_common.util.GsonUtils; import com.siam.package_promotion.entity.CouponsShopRelation; import com.siam.package_promotion.service.CouponsShopRelationService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -20,13 +21,13 @@ @RestController @RequestMapping(value = "/rest/admin/couponsShopRelation") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台优惠卷接口", description = "AdminCouponsShopRelationController") +@Tag(name = "后台优惠卷接口", description = "AdminCouponsShopRelationController") public class AdminCouponsShopRelationController { @Autowired private CouponsShopRelationService couponsShopRelationService; - @ApiOperation(value = "新增优惠卷店铺关系") + @Operation(summary = "新增优惠卷店铺关系") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) CouponsShopRelation param) { BasicResult basicResult = new BasicResult(); @@ -40,7 +41,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) CouponsShopRelatio return basicResult; } - @ApiOperation(value = "优惠卷店铺关系列表查询") + @Operation(summary = "优惠卷店铺关系列表查询") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) CouponsShopRelation param) { BasicResult basicResult = new BasicResult(); diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminPaperworkPushController.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminPaperworkPushController.java index 4b55567..bf928fb 100644 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminPaperworkPushController.java +++ b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/admin/AdminPaperworkPushController.java @@ -8,8 +8,9 @@ import com.siam.package_promotion.entity.PaperworkPush; import com.siam.package_promotion.service.PaperworkPushService; import com.siam.package_user.model.example.MemberExample; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -20,7 +21,7 @@ @RestController @RequestMapping(value = "/rest/admin/paperworkPush") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台文案推送模块相关接口", description = "AdminPaperworkPushController") +@Tag(name = "后台文案推送模块相关接口", description = "AdminPaperworkPushController") public class AdminPaperworkPushController { @Autowired @@ -32,7 +33,7 @@ public class AdminPaperworkPushController { @Autowired private AliyunSms aliyunSms; - @ApiOperation(value = "文案列表") + @Operation(summary = "文案列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) PaperworkPush paperworkPush){ BasicData basicResult = new BasicData(); @@ -41,7 +42,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) PaperworkPush paperw return BasicResult.success(page); } - @ApiOperation(value = "文案创建") + @Operation(summary = "文案创建") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) PaperworkPush paperworkPush){ BasicResult basicResult = new BasicResult(); @@ -57,7 +58,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) PaperworkPush pape } - @ApiOperation(value = "文案修改") + @Operation(summary = "文案修改") @PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) PaperworkPush paperworkPush){ BasicResult basicResult = new BasicResult(); @@ -72,7 +73,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) PaperworkPush pape } - @ApiOperation(value = "文案删除") + @Operation(summary = "文案删除") @DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) PaperworkPush param){ BasicResult basicResult = new BasicResult(); @@ -85,7 +86,7 @@ public BasicResult delete(@RequestBody @Validated(value = {}) PaperworkPush para return basicResult; } - @ApiOperation(value = "推送") + @Operation(summary = "推送") @PutMapping(value = "/push") public BasicResult push(@RequestBody @Validated(value = {}) PaperworkPush paperworkPush){ BasicResult basicResult = new BasicResult(); diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/member/AdvertisementController.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/member/AdvertisementController.java index 0493076..941911a 100644 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/member/AdvertisementController.java +++ b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/member/AdvertisementController.java @@ -6,8 +6,9 @@ import com.siam.package_promotion.entity.Advertisement; import com.siam.package_promotion.model.param.AdvertisementParam; import com.siam.package_promotion.service.AdvertisementService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -21,12 +22,12 @@ @RestController @RequestMapping(value = "/rest/advertisement") @Transactional(rollbackFor = Exception.class) -@Api(tags = "广告轮播图模块相关接口", description = "AdvertisementController") +@Tag(name = "广告轮播图模块相关接口", description = "AdvertisementController") public class AdvertisementController { @Autowired private AdvertisementService advertisementService; - @ApiOperation(value = "广告轮播图列表") + @Operation(summary = "广告轮播图列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) AdvertisementParam advertisement){ BasicData basicResult = new BasicData(); diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/member/CouponsMemberRelationController.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/member/CouponsMemberRelationController.java index 13b3733..d3ec0e1 100644 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/member/CouponsMemberRelationController.java +++ b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/member/CouponsMemberRelationController.java @@ -9,22 +9,28 @@ import com.siam.package_user.auth.cache.MemberSessionManager; import com.siam.package_user.entity.Member; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.Map; @RestController @RequestMapping(value = "/rest/member/couponsMemberRelation") @Transactional(rollbackFor = Exception.class) -@Api(tags = "优惠卷用关系接口", description = "CouponsMemberRelationController") +@Tag(name = "优惠卷用关系接口", description = "CouponsMemberRelationController") public class CouponsMemberRelationController { @Autowired @@ -36,7 +42,7 @@ public class CouponsMemberRelationController { @Autowired private MemberSessionManager memberSessionManager; - @ApiOperation(value = "新增优惠卷用户关系") + @Operation(summary = "新增优惠卷用户关系") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) CouponsMemberRelation couponsMemberRelation) { BasicResult basicResult = new BasicResult(); @@ -49,11 +55,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) CouponsMemberRelat return basicResult; } - @ApiOperation(value = "查看优惠卷关系详情(包含关联优惠卷)") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "主键id", required = true, paramType = "query", dataType = "Integer"), - }) - @PostMapping(value = "/selectById") + @Operation(summary = "查看优惠卷关系详情(包含关联优惠卷)")@PostMapping(value = "/selectById") public BasicResult selectById(@RequestBody @Validated(value = {}) CouponsMemberRelation param){ BasicData basicResult = new BasicData(); @@ -67,21 +69,7 @@ public BasicResult selectById(@RequestBody @Validated(value = {}) CouponsMemberR } - @ApiOperation(value = "优惠卷用户关系列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "主键id", required = false, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "couponsId", value = "优惠卷id", required = false, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "couponsName", value = "优惠卷名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "memberId", value = "用户id", required = false, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "startTime", value = "生效时间", required = false, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "endTime", value = "过期时间", required = false, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "isUsed", value = "是否已经使用,0=未使用,1=已使用", required = false, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "isExpired", value = "是否过期,0=未过期,1=已过期", required = false, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "isValid", value = "是否生效,0-未生效,1-生效中", required = false, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - }) - @PostMapping(value = "/list") + @Operation(summary = "优惠卷用户关系列表")@PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) CouponsMemberRelation couponsMemberRelation, HttpServletRequest request) { BasicData basicResult = new BasicData(); Member loginMember = memberSessionManager.getSession(TokenUtil.getToken()); @@ -93,7 +81,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) CouponsMemberRelatio return BasicResult.success(page); } - @ApiOperation(value = "查询优惠卷数量") + @Operation(summary = "查询优惠卷数量") @PostMapping(value = "/selectCounts") public BasicResult selectCounts( HttpServletRequest request){ BasicData basicResult = new BasicData(); diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/member/FullReductionRuleController.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/member/FullReductionRuleController.java index d640f37..98ba382 100644 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/member/FullReductionRuleController.java +++ b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/member/FullReductionRuleController.java @@ -6,10 +6,16 @@ import com.siam.package_common.exception.StoneCustomerException; import com.siam.package_promotion.entity.FullReductionRule; import com.siam.package_promotion.service.FullReductionRuleService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -18,23 +24,13 @@ @RestController @RequestMapping(value = "/rest/fullReductionRule") @Transactional(rollbackFor = Exception.class) -@Api(tags = "满减规则模块相关接口", description = "FullReductionRuleController") +@Tag(name = "满减规则模块相关接口", description = "FullReductionRuleController") public class FullReductionRuleController { @Autowired private FullReductionRuleService fullReductionRuleService; - @ApiOperation(value = "满减规则列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "主键id", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "name", value = "满减规则名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "status", value = "状态", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "limitedPrice", value = "分类名称", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "reducedPrice", value = "品牌id", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - }) - @PostMapping(value = "/list") + @Operation(summary = "满减规则列表")@PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) FullReductionRule fullReductionRule){ BasicData basicResult = new BasicData(); @@ -47,11 +43,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) FullReductionRule fu return BasicResult.success(page); } - /*@ApiOperation(value = "查看满减规则详情") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "主键id", required = true, paramType = "query", dataType = "Integer"), - }) - @PostMapping(value = "/selectById") + /*@Operation(summary = "查看满减规则详情")@PostMapping(value = "/selectById") public BasicResult selectById(@RequestParam(value = "id", required = true) int id){ BasicData basicResult = new BasicData(); diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/member/MemberAdvertisementController.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/member/MemberAdvertisementController.java index c3203e9..96b741f 100644 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/member/MemberAdvertisementController.java +++ b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/member/MemberAdvertisementController.java @@ -13,10 +13,16 @@ import com.siam.package_user.auth.cache.MemberSessionManager; import com.siam.package_user.entity.Member; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -26,14 +32,14 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.io.IOException; @Slf4j @RestController @RequestMapping(value = "/rest/member/advertisement") @Transactional(rollbackFor = Exception.class) -@Api(tags = "用户广告轮播图模块相关接口", description = "MemberAdvertisementController") +@Tag(name = "用户广告轮播图模块相关接口", description = "MemberAdvertisementController") public class MemberAdvertisementController { @Autowired @@ -48,19 +54,7 @@ public class MemberAdvertisementController { @Autowired private MemberSessionManager memberSessionManager; - @ApiOperation(value = "广告轮播图列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "广告轮播图表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "imageName", value = "轮播图名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "imagePath", value = "轮播图路径", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "description", value = "说明", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "type", value = "轮播图类型 1=首页轮播图 2=菜单页轮播图", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "sortNumber", value = "排序号", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "imageLinkUrl", value = "点击轮播图跳转的链接", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) - @PostMapping(value = "/list") + @Operation(summary = "广告轮播图列表")@PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) AdvertisementParam advertisement, HttpServletRequest request){ BasicData basicResult = new BasicData(); Member loginMember = memberSessionManager.getSession(TokenUtil.getToken()); diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantAdvertisementController.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantAdvertisementController.java index a17c6ca..fda4c38 100644 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantAdvertisementController.java +++ b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantAdvertisementController.java @@ -7,10 +7,16 @@ import com.siam.package_promotion.entity.Advertisement; import com.siam.package_promotion.model.param.AdvertisementParam; import com.siam.package_promotion.service.AdvertisementService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -21,25 +27,13 @@ @RestController @RequestMapping(value = "/rest/merchant/advertisement") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端广告轮播图模块相关接口【暂无调用】", description = "MerchantAdvertisementController") +@Tag(name = "商家端广告轮播图模块相关接口【暂无调用】", description = "MerchantAdvertisementController") public class MerchantAdvertisementController { @Autowired private AdvertisementService advertisementService; - @ApiOperation(value = "广告轮播图列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "广告轮播图表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "imageName", value = "轮播图名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "imagePath", value = "轮播图路径", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "description", value = "说明", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "type", value = "轮播图类型 1=首页轮播图 2=菜单页轮播图", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "sortNumber", value = "排序号", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "imageLinkUrl", value = "点击轮播图跳转的链接", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - }) - @PostMapping(value = "/list") + @Operation(summary = "广告轮播图列表")@PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) AdvertisementParam advertisement){ BasicData basicResult = new BasicData(); Page page = advertisementService.getListByPage(advertisement); @@ -47,16 +41,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) AdvertisementParam a return BasicResult.success(page); } - @ApiOperation(value = "新增广告轮播图") - @ApiImplicitParams({ - @ApiImplicitParam(name = "imageName", value = "轮播图名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "imagePath", value = "轮播图路径", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "description", value = "说明", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "type", value = "轮播图类型 1=首页轮播图 2=菜单页轮播图", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "sortNumber", value = "排序号", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "imageLinkUrl", value = "点击轮播图跳转的链接", required = false, paramType = "query", dataType = "string"), - }) - @PostMapping(value = "/insert") + @Operation(summary = "新增广告轮播图")@PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) AdvertisementParam advertisement){ BasicResult basicResult = new BasicResult(); @@ -71,17 +56,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) AdvertisementParam } - @ApiOperation(value = "修改广告轮播图") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "广告轮播图主键id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "imageName", value = "轮播图名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "imagePath", value = "轮播图路径", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "description", value = "说明", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "type", value = "轮播图类型 1=首页轮播图 2=菜单页轮播图", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "sortNumber", value = "排序号", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "imageLinkUrl", value = "点击轮播图跳转的链接", required = false, paramType = "query", dataType = "string"), - }) - @PutMapping(value = "/update") + @Operation(summary = "修改广告轮播图")@PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) AdvertisementParam advertisement){ BasicResult basicResult = new BasicResult(); @@ -99,11 +74,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) AdvertisementParam } - @ApiOperation(value = "删除广告轮播图") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "广告轮播图主键id", required = true, paramType = "query", dataType = "int") - }) - @DeleteMapping(value = "/delete") + @Operation(summary = "删除广告轮播图")@DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) AdvertisementParam param){ BasicResult basicResult = new BasicResult(); diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantCouponsController.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantCouponsController.java index bffda98..653d616 100644 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantCouponsController.java +++ b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantCouponsController.java @@ -20,16 +20,22 @@ import com.siam.package_promotion.service.CouponsService; import com.siam.package_promotion.service.CouponsShopRelationService; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.Date; import java.util.List; import java.util.Map; @@ -37,7 +43,7 @@ @RestController @RequestMapping(value = "/rest/merchant/coupons") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端优惠卷接口", description = "MerchantCouponsController") +@Tag(name = "商家端优惠卷接口", description = "MerchantCouponsController") public class MerchantCouponsController { @Autowired @@ -58,21 +64,7 @@ public class MerchantCouponsController { @Autowired private MerchantSessionManager merchantSessionManager; - @ApiOperation(value = "新增优惠卷") - @ApiImplicitParams({ - @ApiImplicitParam(name = "name", value = "优惠卷名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "preferentialType", value = "优惠类型,1=折扣,2=满减", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "discountAmount", value = "折扣额度", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "limitedPrice", value = "满足价格(元,满足该价格才能使用)", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "reducedPrice", value = "减价额度(元)", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "description", value = "使用规则描述", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "validType", value = "时效:1绝对时效(领取后XXX-XXX时间段有效)  2相对时效(领取后N天有效)", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "validStartTime", value = "使用开始时间", required = true, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "validEndTime", value = "使用结束时间", required = true, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "validDays", value = "自领取之日起有效天数", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "isDelete", value = "是否已删除", required = true, paramType = "query", dataType = "Boolean"), - }) - @PostMapping(value = "/insert") + @Operation(summary = "新增优惠卷")@PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) Coupons coupons, HttpServletRequest request) { BasicResult basicResult = new BasicResult(); @@ -110,22 +102,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) Coupons coupons, H } @MerchantPermission - @ApiOperation(value = "修改优惠卷-TODO") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "主键id", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "name", value = "优惠卷名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "preferentialType", value = "优惠类型,1=折扣,2=满减", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "discountAmount", value = "折扣额度", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "limitedPrice", value = "满足价格(元,满足该价格才能使用)", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "reducedPrice", value = "减价额度(元)", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "description", value = "使用规则描述", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "validType", value = "时效:1绝对时效(领取后XXX-XXX时间段有效)  2相对时效(领取后N天有效)", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "validStartTime", value = "使用开始时间", required = true, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "validEndTime", value = "使用结束时间", required = true, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "validDays", value = "自领取之日起有效天数", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "isDelete", value = "是否已删除", required = true, paramType = "query", dataType = "Boolean"), - }) - @PutMapping(value = "/update") + @Operation(summary = "修改优惠卷-TODO")@PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) Coupons coupons, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); @@ -139,11 +116,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) Coupons coupons, H } @MerchantPermission - @ApiOperation(value = "删除优惠卷") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "主键id", required = true, paramType = "query", dataType = "Integer"), - }) - @DeleteMapping(value = "/delete") + @Operation(summary = "删除优惠卷")@DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) Coupons param){ BasicResult basicResult = new BasicResult(); @@ -155,11 +128,7 @@ public BasicResult delete(@RequestBody @Validated(value = {}) Coupons param){ return basicResult; } - @ApiOperation(value = "查看优惠卷详情(包含关联商品)") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "主键id", required = true, paramType = "query", dataType = "Integer"), - }) - @PostMapping(value = "/selectById") + @Operation(summary = "查看优惠卷详情(包含关联商品)")@PostMapping(value = "/selectById") public BasicResult selectById(@RequestBody @Validated(value = {}) Coupons param){ BasicData basicResult = new BasicData(); @@ -172,24 +141,7 @@ public BasicResult selectById(@RequestBody @Validated(value = {}) Coupons param) return basicResult; } - @ApiOperation(value = "优惠卷列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "主键id", required = false, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "name", value = "优惠卷名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "preferentialType", value = "优惠类型,1=折扣,2=满减", required = false, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "discountAmount", value = "折扣额度", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "limitedPrice", value = "满足价格(元,满足该价格才能使用)", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "reducedPrice", value = "减价额度(元)", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "description", value = "使用规则描述", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "validType", value = "时效:1绝对时效(领取后XXX-XXX时间段有效)  2相对时效(领取后N天有效)", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "validStartTime", value = "使用开始时间", required = true, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "validEndTime", value = "使用结束时间", required = true, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "validDays", value = "自领取之日起有效天数", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "isDelete", value = "是否已删除", required = true, paramType = "query", dataType = "Boolean"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - }) - @PostMapping(value = "/list") + @Operation(summary = "优惠卷列表")@PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) CouponsDto couponsDto, HttpServletRequest request) { BasicData basicResult = new BasicData(); @@ -204,22 +156,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) CouponsDto couponsDt return BasicResult.success(page); } - @ApiOperation(value = "优惠卷时间修改(延长)") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "主键id", required = false, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "name", value = "优惠卷名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "preferentialType", value = "优惠类型,1=折扣,2=满减", required = false, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "discountAmount", value = "折扣额度", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "limitedPrice", value = "满足价格(元,满足该价格才能使用)", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "reducedPrice", value = "减价额度(元)", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "description", value = "使用规则描述", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "validType", value = "时效:1绝对时效(领取后XXX-XXX时间段有效)  2相对时效(领取后N天有效)", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "validStartTime", value = "使用开始时间", required = true, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "validEndTime", value = "使用结束时间", required = true, paramType = "query", dataType = "Date"), - @ApiImplicitParam(name = "validDays", value = "自领取之日起有效天数", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "isDelete", value = "是否已删除", required = true, paramType = "query", dataType = "Boolean"), - }) - @PostMapping(value = "/updateEndTime") + @Operation(summary = "优惠卷时间修改(延长)")@PostMapping(value = "/updateEndTime") public BasicResult updateEndTime(@RequestBody @Validated(value = {}) Coupons coupons){ BasicResult basicResult = new BasicResult(); diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantCouponsGoodsRelationController.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantCouponsGoodsRelationController.java index 57c0d3b..24de977 100644 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantCouponsGoodsRelationController.java +++ b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantCouponsGoodsRelationController.java @@ -5,10 +5,16 @@ import com.siam.package_common.util.GsonUtils; import com.siam.package_promotion.entity.CouponsGoodsRelation; import com.siam.package_promotion.service.CouponsGoodsRelationService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -19,19 +25,13 @@ @RestController @RequestMapping(value = "/rest/merchant/couponsGoodsRelation") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端优惠卷接口", description = "MerchantCouponsGoodsRelationController") +@Tag(name = "商家端优惠卷接口", description = "MerchantCouponsGoodsRelationController") public class MerchantCouponsGoodsRelationController { @Autowired private CouponsGoodsRelationService couponsGoodsRelationService; - @ApiOperation(value = "新增优惠卷商品关系") - @ApiImplicitParams({ - @ApiImplicitParam(name = "couponsId", value = "优惠卷id", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsIdList", value = "商品id集合(list)", required = true, paramType = "body", dataType = "string"), - - }) - @PostMapping(value = "/insert") + @Operation(summary = "新增优惠卷商品关系")@PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) CouponsGoodsRelation param) { BasicResult basicResult = new BasicResult(); @@ -44,16 +44,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) CouponsGoodsRelati return basicResult; } - @ApiOperation(value = "优惠卷商品关系列表查询") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "主键id", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "goodsId", value = "商品id", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "couponsId", value = "优惠卷id", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - - }) - @PostMapping(value = "/list") + @Operation(summary = "优惠卷商品关系列表查询")@PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) CouponsGoodsRelation couponsGoodsRelation) { BasicResult basicResult = new BasicResult(); diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantCouponsMemberRelationController.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantCouponsMemberRelationController.java index 4d5c257..523cead 100644 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantCouponsMemberRelationController.java +++ b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantCouponsMemberRelationController.java @@ -11,10 +11,16 @@ import com.siam.package_promotion.service.CouponsMemberRelationService; import com.siam.package_user.entity.Member; import com.siam.package_user.feign.MemberFeignApi; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -27,7 +33,7 @@ @RestController @RequestMapping(value = "/rest/merchant/couponsMemberRelation") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端优惠卷用关系接口", description = "MerchantCouponsMemberRelationController") +@Tag(name = "商家端优惠卷用关系接口", description = "MerchantCouponsMemberRelationController") public class MerchantCouponsMemberRelationController { @Autowired @@ -43,11 +49,7 @@ public class MerchantCouponsMemberRelationController { private AliyunSms aliyunSms; - @ApiOperation(value = "赠送优惠卷") - @ApiImplicitParams({ - @ApiImplicitParam(name = "couponsId", value = "优惠卷id", required = false, paramType = "query", dataType = "int") - }) - @PostMapping(value = "/giveCoupons") + @Operation(summary = "赠送优惠卷")@PostMapping(value = "/giveCoupons") public BasicResult giveCoupons(@RequestBody @Validated(value = {}) CouponsMemberRelation param) { BasicResult basicResult = new BasicResult(); @@ -102,12 +104,7 @@ public BasicResult giveCoupons(@RequestBody @Validated(value = {}) CouponsMember return basicResult; } - @ApiOperation(value = "赠送优惠卷(单发)") - @ApiImplicitParams({ - @ApiImplicitParam(name = "couponsId", value = "优惠卷id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "memberId", value = "用户id", required = false, paramType = "query", dataType = "int") - }) - @PostMapping(value = "/giveSingleCoupons") + @Operation(summary = "赠送优惠卷(单发)")@PostMapping(value = "/giveSingleCoupons") public BasicResult giveSingleCoupons(@RequestBody @Validated(value = {}) CouponsMemberRelation param) { BasicResult basicResult = new BasicResult(); diff --git a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantFullReductionRuleController.java b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantFullReductionRuleController.java index 36e8c52..c43ba92 100644 --- a/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantFullReductionRuleController.java +++ b/siam-promotion/promotion-provider/src/main/java/com/siam/package_promotion/controller/merchant/MerchantFullReductionRuleController.java @@ -12,21 +12,27 @@ import com.siam.package_merchant.auth.cache.MerchantSessionManager; import com.siam.package_merchant.entity.Merchant; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; @RestController @RequestMapping(value = "/rest/merchant/fullReductionRule") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端满减规则模块相关接口", description = "MerchantFullReductionRuleController") +@Tag(name = "商家端满减规则模块相关接口", description = "MerchantFullReductionRuleController") public class MerchantFullReductionRuleController { @Autowired @@ -38,14 +44,7 @@ public class MerchantFullReductionRuleController { @Autowired private MerchantSessionManager merchantSessionManager; - @ApiOperation(value = "新增满减规则") - @ApiImplicitParams({ - @ApiImplicitParam(name = "name", value = "满减规则名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "status", value = "状态", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "limitedPrice", value = "分类名称", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "reducedPrice", value = "品牌id", required = true, paramType = "query", dataType = "BigDecimal") - }) - @PostMapping(value = "/insert") + @Operation(summary = "新增满减规则")@PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) FullReductionRule fullReductionRule, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); @@ -62,15 +61,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) FullReductionRule } @MerchantPermission - @ApiOperation(value = "修改满减规则") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "主键id", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "name", value = "满减规则名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "status", value = "状态", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "limitedPrice", value = "分类名称", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "reducedPrice", value = "品牌id", required = true, paramType = "query", dataType = "BigDecimal") - }) - @PutMapping(value = "/update") + @Operation(summary = "修改满减规则")@PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) FullReductionRule fullReductionRule, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); @@ -90,11 +81,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) FullReductionRule } @MerchantPermission - @ApiOperation(value = "删除满减规则") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "主键id", required = true, paramType = "query", dataType = "Integer"), - }) - @DeleteMapping(value = "/delete") + @Operation(summary = "删除满减规则")@DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) FullReductionRule param){ BasicResult basicResult = new BasicResult(); @@ -118,17 +105,7 @@ public BasicResult delete(@RequestBody @Validated(value = {}) FullReductionRule - @ApiOperation(value = "满减规则列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "主键id", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "name", value = "满减规则名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "status", value = "状态", required = true, paramType = "query", dataType = "Integer"), - @ApiImplicitParam(name = "limitedPrice", value = "分类名称", required = false, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "reducedPrice", value = "品牌id", required = true, paramType = "query", dataType = "BigDecimal"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - }) - @PostMapping(value = "/list") + @Operation(summary = "满减规则列表")@PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) FullReductionRule fullReductionRule, HttpServletRequest request) { BasicData basicResult = new BasicData(); diff --git a/siam-promotion/promotion-provider/src/main/resources/application-local.yml b/siam-promotion/promotion-provider/src/main/resources/application-local.yml index 864784b..abd932c 100644 --- a/siam-promotion/promotion-provider/src/main/resources/application-local.yml +++ b/siam-promotion/promotion-provider/src/main/resources/application-local.yml @@ -5,9 +5,9 @@ server: spring: #mysql datasource: - url: jdbc:mysql://127.0.0.1:3306/siam_cloud?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8 + url: jdbc:mysql://127.0.0.1:3306/siam_cloud?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true username: root - password: root + password: 123456 # #mongodb(默认时没有账号密码的) # # application: @@ -75,6 +75,18 @@ spring: application: name: promotion-siam + # Nacos注册中心/配置中心 + cloud: + nacos: + discovery: + server-addr: 127.0.0.1:8848 + config: + server-addr: 127.0.0.1:8848 + file-extension: yaml + config: + import: + - optional:nacos:${spring.application.name}-local.yaml + #配置文件上传大小限制 servlet: multipart: @@ -142,17 +154,7 @@ mybatis-plus: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl -#eureka配置 -eureka: - client: - service-url: - defaultZone: http://127.0.0.1:9000/eureka/ - register-with-eureka: true - fetch-registry: true - instance: - #配置使用ip地址来注册(默认是主机名称) - prefer-ip-address: true - #心跳检测暂时不配置 +# Nacos注册中心/配置中心 #feign内部服务调用超时配置 feign: @@ -173,24 +175,31 @@ rocketmq: # Seata Config seata: - application-id: promotion-service + application-id: ${spring.application.name} tx-service-group: my_test_tx_group service: vgroup-mapping: - # 此处配置对应Server端配置registry.eureka.application的值 my_test_tx_group: default registry: - type: eureka - eureka: - service-url: http://127.0.0.1:9000/eureka/ - weight: 1 + type: nacos + nacos: + application: seata-server + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public + config: + type: nacos + nacos: + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public #springboot admin相关配置 management: endpoints: web: exposure: - include: "*" #'prometheus,health' + include: "health,prometheus,info" exclude: "shutdown" base-path: /actuator endpoint: @@ -215,6 +224,8 @@ management: enabled: false elasticsearch: enabled: false + mail: + enabled: false #日志配置 logging: diff --git a/siam-promotion/promotion-provider/src/test/java/com/siam/package_promotion/ImageComposeTest.java b/siam-promotion/promotion-provider/src/test/java/com/siam/package_promotion/ImageComposeTest.java index bab4869..81614ce 100644 --- a/siam-promotion/promotion-provider/src/test/java/com/siam/package_promotion/ImageComposeTest.java +++ b/siam-promotion/promotion-provider/src/test/java/com/siam/package_promotion/ImageComposeTest.java @@ -1,10 +1,11 @@ package com.siam.package_promotion; import com.alibaba.fastjson.JSONObject; -import sun.font.FontDesignMetrics; import javax.imageio.ImageIO; import java.awt.*; +import java.awt.font.FontRenderContext; +import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.*; import java.net.HttpURLConnection; @@ -18,33 +19,9 @@ public class ImageComposeTest { public static void main(String[] args) throws IOException { CompoundImage("https://deerspot.oss-cn-hangzhou.aliyuncs.com/test/siamCompose.png", "https://deerspot.oss-cn-hangzhou.aliyuncs.com/test/eb831e8f0b42b8b3a8b4360c11a2b5e.jpg", "", "C:\\Users\\Administrator\\Desktop\\testComponse.png", "postion"); - - /*try { - String destUrl = "https://ibsbjstar.ccb.com.cn/NCCB_Encoder/Encoder?CODE=EUSo4Twu6YRk2JDPJ9OnpfgrdDObpGwKBGOTqVwnBfWAvjCP5UOFuig6hySmrww2hXVIqDgb5NUOrvwI5NRuqtQ3pXcRVh"; - HttpURLConnection httpUrl = (HttpURLConnection) new URL(destUrl).openConnection(); - httpUrl.connect(); - File file = inputStreamToFile(httpUrl.getInputStream(),"url.png"); - System.out.println("111====>>>>"+file.getPath()); - httpUrl.disconnect(); - } catch (Exception e) { - e.printStackTrace(); - }*/ - - -// qrcode(); } - - /** - * 图片合成 - * @param mainImgPath 主图片路径 - * @param qrcodePath 二维码路径 - * @param text 文字 - * @param compoundPath 图片合成保存路径 - * @param databasePath 数据库保存路径 - * @return 保存路径 - */ - public static String CompoundImage(String mainImgPath, String qrcodePath,String text,String compoundPath,String databasePath) throws IOException { + public static String CompoundImage(String mainImgPath, String qrcodePath, String text, String compoundPath, String databasePath) throws IOException { String destUrl = mainImgPath; HttpURLConnection httpUrl = (HttpURLConnection) new URL(destUrl).openConnection(); httpUrl.connect(); @@ -53,33 +30,29 @@ public static String CompoundImage(String mainImgPath, String qrcodePath,String HttpURLConnection httpUrl_qrcode = (HttpURLConnection) new URL(destUrl_qrcode).openConnection(); httpUrl_qrcode.connect(); - String ewmurl=""; + String ewmurl = ""; try { - //1、获取主图片 - BufferedImage big = ImageIO.read(httpUrl.getInputStream());//mainImgPath + BufferedImage big = ImageIO.read(httpUrl.getInputStream()); URL url = new URL("https://img-blog.csdn.net/20150906104118760"); - //2、拿到二维码 - BufferedImage erweima = ImageIO.read(httpUrl_qrcode.getInputStream());//qrcodePath + BufferedImage erweima = ImageIO.read(httpUrl_qrcode.getInputStream()); int width = 1080; int height = 1854; Image image = big.getScaledInstance(width, height, Image.SCALE_SMOOTH); BufferedImage bufferedImage2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR); - //3、开始绘图 Graphics2D g = bufferedImage2.createGraphics(); g.drawImage(image, 0, 0, null); g.drawImage(erweima, 20, 1500, 300, 300, null); - Font font = new Font("微软雅黑", Font.BOLD, 38); + Font font = new Font("SansSerif", Font.BOLD, 38); g.setFont(font); g.setPaint(Color.BLACK); - //4、设置位置 int wordWidth = getWordWidth(font, text); int i = width / 2; int i1 = (i - wordWidth) / 2; - int numWidth=i+i1; - g.drawString(text, numWidth-10, 310+28); + int numWidth = i + i1; + g.drawString(text, numWidth - 10, 310 + 28); g.dispose(); - ewmurl =compoundPath; + ewmurl = compoundPath; ImageIO.write(bufferedImage2, "jpg", new File(ewmurl)); System.out.println("图片生成完毕"); ewmurl = databasePath; @@ -91,136 +64,41 @@ public static String CompoundImage(String mainImgPath, String qrcodePath,String return ewmurl; } - -// /** -// * 生成二维码 -// * @param backLink 扫码回调链接 -// * @param savePath 二维码保存路径 -// * @return 返回保存路径(用于保存数据库) -// * @throws IOException -// */ -// public static String createQRCode(String backLink,String savePath) throws IOException { -// //计算二维码图片的高宽比 -// int v = 6; -// int width = 67 + 12 * (v - 1); -// int height = 67 + 12 * (v - 1); -// -// Map x = new HashMap(); -// x.put("setQrcodeErrorCorrect", 'L'); -// x.put("setQrcodeEncodeMode", 'B');//注意版本信息 N代表数字 、A代表 a-z,A-Z、B代表 其他) -// x.put("setQrcodeVersion", v); -// -// byte[] d = backLink.getBytes("utf-8");//汉字转格式需要抛出异常 -// -// //缓冲区 -// BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR); -// -// //绘图 -// Graphics2D gs = bufferedImage.createGraphics(); -// -// gs.setBackground(Color.WHITE); -// gs.setColor(Color.BLACK); -// gs.clearRect(0, 0, width, height); -// -// //偏移量 -// int pixoff = 2; -// -// if (d.length > 0 && d.length < 120) { -// boolean[][] s = x.calQrcode(d); -// -// for (int i = 0; i < s.length; i++) { -// for (int j = 0; j < s.length; j++) { -// if (s[j][i]) { -// gs.fillRect(j * 3 + pixoff, i * 3 + pixoff, 3, 3); -// } -// } -// } -// } -// gs.dispose(); -// bufferedImage.flush(); -// //设置图片格式,与输出的路径 -// String url = savePath; -// ImageIO.write(bufferedImage, "png", new File(url)); -// System.out.println("二维码生成完毕"); -// return url; -// } - public static int getWordWidth(Font font, String content) { - FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font); - int width = 0; - for (int i = 0; i < content.length(); i++) { - width += metrics.charWidth(content.charAt(i)); - } - return width; + FontRenderContext frc = new FontRenderContext(new AffineTransform(), true, true); + return (int) font.getStringBounds(content, frc).getWidth(); } - - - - - - - - /** - * 工具类 - * inputStream 转 File - */ - public static File inputStreamToFile(InputStream ins, String name) throws Exception{ + public static File inputStreamToFile(InputStream ins, String name) throws Exception { File file = new File(System.getProperty("java.io.tmpdir") + File.separator + name); if (file.exists()) { return file; } - /*OutputStream os = new FileOutputStream(file); - int bytesRead; - int len = 8192; - byte[] buffer = new byte[len]; - while ((bytesRead = ins.read(buffer, 0, len)) != -1) { - os.write(buffer, 0, bytesRead); - } - os.close();*/ ins.close(); return file; } - - - - - - - - - + // ... rest of the test methods (qrcode, sendPost, getToken) remain unchanged public static void qrcode() { try { URL url = new URL("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + getToken()); - System.out.println(url); HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); - httpURLConnection.setRequestMethod("POST");// 提交模式 - // conn.setConnectTimeout(10000);//连接超时 单位毫秒 - // conn.setReadTimeout(2000);//读取超时 单位毫秒 - // 发送POST请求必须设置如下两行 + httpURLConnection.setRequestMethod("POST"); httpURLConnection.setDoOutput(true); httpURLConnection.setDoInput(true); - // 获取URLConnection对象对应的输出流 PrintWriter printWriter = new PrintWriter(httpURLConnection.getOutputStream()); - // 发送请求参数 JSONObject paramJson = new JSONObject(); - paramJson.put("scene", "inviterId=111");//参数 - paramJson.put("page", "pages/login/choose/choose");//小程序未发布前注释,否则找不到对应的页面,就会生成错误的图片 + paramJson.put("scene", "inviterId=111"); + paramJson.put("page", "pages/login/choose/choose"); paramJson.put("width", 430); -// paramJson.put("auto_color", true); -// paramJson.put("auto_color", false); JSONObject lineColor = new JSONObject(); lineColor.put("r", 0); lineColor.put("g", 0); lineColor.put("b", 0); paramJson.put("line_color", lineColor); printWriter.write(paramJson.toString()); - // flush输出流的缓冲 printWriter.flush(); - //开始获取数据 BufferedInputStream bis = new BufferedInputStream(httpURLConnection.getInputStream()); OutputStream os = new FileOutputStream(new File("C:\\Users\\Administrator\\Desktop\\testQrcode.png")); BufferedImage read = ImageIO.read(httpURLConnection.getInputStream()); @@ -241,13 +119,6 @@ public static void qrcode() { } } - - /** - * 向指定 URL 发送POST方法的请求 - * - * @param url 发送请求的 URL - * @return 所代表远程资源的响应结果 - */ public static String sendPost(String url, Map paramMap) { PrintWriter out = null; BufferedReader in = null; @@ -260,23 +131,16 @@ public static String sendPost(String url, Map paramMap) { } try { URL realUrl = new URL(url); - // 打开和URL之间的连接 URLConnection conn = realUrl.openConnection(); - // 设置通用的请求属性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("Accept-Charset", "utf-8"); conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); - // 发送POST请求必须设置如下两行 conn.setDoOutput(true); conn.setDoInput(true); - // 获取URLConnection对象对应的输出流 out = new PrintWriter(conn.getOutputStream()); - // 发送请求参数 out.print(param); - // flush输出流的缓冲 out.flush(); - // 定义BufferedReader输入流来读取URL的响应 in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8")); String line; while ((line = in.readLine()) != null) { @@ -284,16 +148,10 @@ public static String sendPost(String url, Map paramMap) { } } catch (Exception e) { System.out.println(e); - } - // 使用finally块来关闭输出流、输入流 - finally { + } finally { try { - if (out != null) { - out.close(); - } - if (in != null) { - in.close(); - } + if (out != null) out.close(); + if (in != null) in.close(); } catch (IOException ex) { ex.printStackTrace(); } @@ -303,14 +161,13 @@ public static String sendPost(String url, Map paramMap) { public static String getToken() { try { - Map map = new LinkedHashMap(); + Map map = new LinkedHashMap<>(); map.put("grant_type", "client_credential"); - map.put("appid", "wx2e1a8193d3ed12fe");// 这里我是写在配置类里,需要改成自己的appid - map.put("secret", "2774e3a86dc30fbf1ac63d81b56f2291"); //这里我是写在配置类里,需要改成自己的secret + map.put("appid", "wx2e1a8193d3ed12fe"); + map.put("secret", "2774e3a86dc30fbf1ac63d81b56f2291"); String rt = sendPost("https://api.weixin.qq.com/cgi-bin/token", map); JSONObject json = JSONObject.parseObject(rt); - if (json.getString("access_token") != null || json.getString("access_token") != "") { -// System.out.println("token:" + json.getString("access_token")); + if (json.getString("access_token") != null) { return json.getString("access_token"); } else { return null; @@ -319,6 +176,5 @@ public static String getToken() { e.printStackTrace(); return null; } - } -} \ No newline at end of file +} diff --git a/siam-rider/pom.xml b/siam-rider/pom.xml index c630231..8249005 100644 --- a/siam-rider/pom.xml +++ b/siam-rider/pom.xml @@ -34,8 +34,6 @@ UTF-8 - 1.8 - 1.8 diff --git a/siam-rider/rider-api/pom.xml b/siam-rider/rider-api/pom.xml index a53bf74..e755701 100644 --- a/siam-rider/rider-api/pom.xml +++ b/siam-rider/rider-api/pom.xml @@ -18,8 +18,6 @@ UTF-8 - 1.8 - 1.8 @@ -39,7 +37,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 exec diff --git a/siam-rider/rider-api/src/main/java/com/siam/package_rider/entity/Rider.java b/siam-rider/rider-api/src/main/java/com/siam/package_rider/entity/Rider.java index 57d64f0..abcfef6 100644 --- a/siam-rider/rider-api/src/main/java/com/siam/package_rider/entity/Rider.java +++ b/siam-rider/rider-api/src/main/java/com/siam/package_rider/entity/Rider.java @@ -4,7 +4,7 @@ import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.Date; @@ -50,10 +50,10 @@ public void setEndCreateTime(Date endCreateTime) { /* ##################################### START 扩展字段 #################################### */ - @ApiModelProperty(notes = "用户密码") + @Schema(description = "用户密码") private String password; - @ApiModelProperty(notes = "密码加盐") + @Schema(description = "密码加盐") private String passwordSalt; //门店名称 diff --git a/siam-rider/rider-api/src/main/java/com/siam/package_rider/util/HttpContext.java b/siam-rider/rider-api/src/main/java/com/siam/package_rider/util/HttpContext.java index c64166f..219438c 100644 --- a/siam-rider/rider-api/src/main/java/com/siam/package_rider/util/HttpContext.java +++ b/siam-rider/rider-api/src/main/java/com/siam/package_rider/util/HttpContext.java @@ -3,8 +3,8 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.Map; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; diff --git a/siam-rider/rider-api/src/main/java/com/siam/package_rider/util/TokenUtil.java b/siam-rider/rider-api/src/main/java/com/siam/package_rider/util/TokenUtil.java index 29fd951..09c6d09 100644 --- a/siam-rider/rider-api/src/main/java/com/siam/package_rider/util/TokenUtil.java +++ b/siam-rider/rider-api/src/main/java/com/siam/package_rider/util/TokenUtil.java @@ -6,9 +6,9 @@ import com.siam.package_common.util.ToolUtil; import com.siam.package_rider.entity.Rider; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; /** * Token工具类 diff --git a/siam-rider/rider-provider/pom.xml b/siam-rider/rider-provider/pom.xml index 0adb2da..28605c2 100644 --- a/siam-rider/rider-provider/pom.xml +++ b/siam-rider/rider-provider/pom.xml @@ -18,8 +18,6 @@ UTF-8 - 1.8 - 1.8 @@ -65,51 +63,40 @@ 1.1 - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - 2.1.2.RELEASE - - - + com.alibaba.cloud - spring-cloud-starter-alibaba-seata - 2021.1 - - - io.seata - seata-spring-boot-starter - - + spring-cloud-starter-alibaba-nacos-discovery + - io.seata - seata-spring-boot-starter - 1.3.0 + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config org.springframework.boot spring-boot-starter-actuator - 2.3.3.RELEASE io.micrometer micrometer-registry-prometheus - 1.5.4 net.logstash.logback logstash-logback-encoder - 6.6 + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui @@ -119,7 +106,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 com.siam.package_rider.RiderApplication diff --git a/siam-rider/rider-provider/src/main/java/com/siam/package_rider/RiderApplication.java b/siam-rider/rider-provider/src/main/java/com/siam/package_rider/RiderApplication.java index 1931682..94c2810 100644 --- a/siam-rider/rider-provider/src/main/java/com/siam/package_rider/RiderApplication.java +++ b/siam-rider/rider-provider/src/main/java/com/siam/package_rider/RiderApplication.java @@ -3,12 +3,17 @@ import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @EnableFeignClients("com.siam") -@EnableEurekaClient -@SpringBootApplication(scanBasePackages = "com.siam") +@EnableDiscoveryClient +@SpringBootApplication(scanBasePackages = "com.siam", exclude = { + MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class +}) @MapperScan(basePackages = {"com.siam.**.mapper"}) public class RiderApplication { diff --git a/siam-rider/rider-provider/src/main/java/com/siam/package_rider/config/MybatisPlusConfig.java b/siam-rider/rider-provider/src/main/java/com/siam/package_rider/config/MybatisPlusConfig.java index 968f66d..24072af 100644 --- a/siam-rider/rider-provider/src/main/java/com/siam/package_rider/config/MybatisPlusConfig.java +++ b/siam-rider/rider-provider/src/main/java/com/siam/package_rider/config/MybatisPlusConfig.java @@ -1,6 +1,8 @@ package com.siam.package_rider.config; -import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -19,8 +21,11 @@ public class MybatisPlusConfig { * 分页插件 */ @Bean - public PaginationInterceptor paginationInterceptor() { - return new PaginationInterceptor(); + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); + interceptor.addInnerInterceptor(paginationInnerInterceptor); + return interceptor; } } \ No newline at end of file diff --git a/siam-rider/rider-provider/src/main/java/com/siam/package_rider/config/Swagger2Config.java b/siam-rider/rider-provider/src/main/java/com/siam/package_rider/config/Swagger2Config.java deleted file mode 100644 index 6f08ebc..0000000 --- a/siam-rider/rider-provider/src/main/java/com/siam/package_rider/config/Swagger2Config.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.siam.package_rider.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; - -@Configuration -@EnableSwagger2 -public class Swagger2Config { - - @Bean - public Docket createRestApi() { - return new Docket(DocumentationType.SWAGGER_2) - .apiInfo(apiInfo()) - .select() - .apis(RequestHandlerSelectors.basePackage("com.siam"))//扫描包路径 - .paths(PathSelectors.any()) - .build(); - } - - // 构建api文档的详细信息函数,注意这里的注解引用的是哪个 - private ApiInfo apiInfo() { - return new ApiInfoBuilder() - .title("暹罗外卖-商家服务接口文档")//页面标题 - .description("")//描述 - .version("1.0")//版本号 - .build(); - } -} \ No newline at end of file diff --git a/siam-rider/rider-provider/src/main/java/com/siam/package_rider/controller/admin/AdminRiderController.java b/siam-rider/rider-provider/src/main/java/com/siam/package_rider/controller/admin/AdminRiderController.java index 50d9001..5467bd4 100644 --- a/siam-rider/rider-provider/src/main/java/com/siam/package_rider/controller/admin/AdminRiderController.java +++ b/siam-rider/rider-provider/src/main/java/com/siam/package_rider/controller/admin/AdminRiderController.java @@ -5,8 +5,11 @@ import com.siam.package_common.entity.BasicResult; import com.siam.package_rider.entity.Rider; import com.siam.package_rider.service.RiderService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -20,13 +23,13 @@ @RestController @RequestMapping(value = "/rest/admin/rider") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台商家自配送骑手信息模块相关接口", description = "AdminRiderController") +@Tag(name = "后台商家自配送骑手信息模块相关接口", description = "AdminRiderController") public class AdminRiderController { @Autowired private RiderService riderService; - @ApiOperation(value = "骑手信息列表") + @Operation(summary = "骑手信息列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) Rider param) { BasicData basicResult = new BasicData(); @@ -35,15 +38,8 @@ public BasicResult list(@RequestBody @Validated(value = {}) Rider param) { return BasicResult.success(page); } -// @ApiOperation(value = "骑手信息创建") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "id", value = "骑手信息主键id", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "name", value = "骑手信息名称", required = true, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "detail", value = "商家自配送骑手信息详情描述", required = false, paramType = "query", dataType = "string") -// }) -// @PostMapping(value = "/insert") +// @Operation(summary = "骑手信息创建") +//// @PostMapping(value = "/insert") // public BasicResult insert(Rider rider){ // BasicResult basicResult = new BasicResult(); // @@ -58,15 +54,8 @@ public BasicResult list(@RequestBody @Validated(value = {}) Rider param) { // } // // -// @ApiOperation(value = "骑手信息修改") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "id", value = "骑手信息主键id", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "name", value = "骑手信息名称", required = true, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "detail", value = "商家自配送骑手信息详情描述", required = false, paramType = "query", dataType = "string") -// }) -// @PutMapping(value = "/update") +// @Operation(summary = "骑手信息修改") +//// @PutMapping(value = "/update") // public BasicResult update(Rider rider){ // BasicResult basicResult = new BasicResult(); // @@ -80,11 +69,8 @@ public BasicResult list(@RequestBody @Validated(value = {}) Rider param) { // } // // -// @ApiOperation(value = "骑手信息删除") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "id", value = "骑手信息主键id集合(批量删除时id以逗号分隔)", required = true, paramType = "query", dataType = "String") -// }) -// @DeleteMapping(value = "/delete") +// @Operation(summary = "骑手信息删除") +//// @DeleteMapping(value = "/delete") // public BasicResult delete(@RequestParam(value = "ids") List ids){ // BasicResult basicResult = new BasicResult(); // for (Integer id : ids) { diff --git a/siam-rider/rider-provider/src/main/java/com/siam/package_rider/controller/member/WxLoginController.java b/siam-rider/rider-provider/src/main/java/com/siam/package_rider/controller/member/WxLoginController.java index dd89d72..1af63ca 100644 --- a/siam-rider/rider-provider/src/main/java/com/siam/package_rider/controller/member/WxLoginController.java +++ b/siam-rider/rider-provider/src/main/java/com/siam/package_rider/controller/member/WxLoginController.java @@ -8,7 +8,8 @@ import com.siam.package_weixin_basic.config.WxEncrypted; import com.siam.package_weixin_basic.config.WxSession; import com.siam.package_weixin_basic.util.WxdecodeUtils; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.http.HttpMethod; @@ -90,7 +91,7 @@ public WxEncrypted getWxUserInfo(String code, String iv, String encryptedData) t return null; } - @ApiOperation(value = "获取微信手机号") + @Operation(summary = "获取微信手机号") @PostMapping(value = "/getWxPhone") public BasicResult getWxPhone(@RequestBody WxCode wxCode) throws Exception { BasicData basicResult = new BasicData(); diff --git a/siam-rider/rider-provider/src/main/java/com/siam/package_rider/controller/merchant/MerchantRiderController.java b/siam-rider/rider-provider/src/main/java/com/siam/package_rider/controller/merchant/MerchantRiderController.java index 3dc3f3a..5d3f03f 100644 --- a/siam-rider/rider-provider/src/main/java/com/siam/package_rider/controller/merchant/MerchantRiderController.java +++ b/siam-rider/rider-provider/src/main/java/com/siam/package_rider/controller/merchant/MerchantRiderController.java @@ -10,48 +10,33 @@ import com.siam.package_merchant.util.TokenUtil; import com.siam.package_rider.entity.Rider; import com.siam.package_rider.service.RiderService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.Date; @RestController @RequestMapping(value = "/rest/merchant/rider") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端商家自配送骑手信息模块相关接口", description = "MerchantRiderController") +@Tag(name = "商家端商家自配送骑手信息模块相关接口", description = "MerchantRiderController") public class MerchantRiderController { @Autowired private RiderService riderService; -// @Autowired -// private MerchantService merchantService; - @Autowired private MerchantSessionManager merchantSessionManager; - @ApiOperation(value = "骑手信息列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "商品名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "detail", value = "商家自配送骑手信息详情描述", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - }) + @Operation(summary = "骑手信息列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) Rider rider, HttpServletRequest request){ BasicData basicResult = new BasicData(); - //获取当前登录用户绑定的门店编号 Merchant loginMerchant = merchantSessionManager.getSession(TokenUtil.getToken()); rider.setShopId(loginMerchant.getShopId()); @@ -60,19 +45,11 @@ public BasicResult list(@RequestBody @Validated(value = {}) Rider rider, HttpSer return BasicResult.success(page); } - @ApiOperation(value = "骑手信息创建") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "骑手信息主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "骑手信息名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "detail", value = "商家自配送骑手信息详情描述", required = false, paramType = "query", dataType = "string") - }) + @Operation(summary = "骑手信息创建") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) Rider rider, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); - //获取当前登录用户绑定的门店编号 Merchant loginMerchant = merchantSessionManager.getSession(TokenUtil.getToken()); rider.setShopId(loginMerchant.getShopId()); @@ -87,19 +64,11 @@ public BasicResult insert(@RequestBody @Validated(value = {}) Rider rider, HttpS } - @ApiOperation(value = "骑手信息修改") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "骑手信息主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "骑手信息名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "detail", value = "商家自配送骑手信息详情描述", required = false, paramType = "query", dataType = "string") - }) + @Operation(summary = "骑手信息修改") @PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) Rider rider, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); - //获取当前登录用户绑定的门店编号 Merchant loginMerchant = merchantSessionManager.getSession(TokenUtil.getToken()); Rider dbRider = riderService.selectByPrimaryKey(rider.getId()); @@ -119,15 +88,11 @@ public BasicResult update(@RequestBody @Validated(value = {}) Rider rider, HttpS } - @ApiOperation(value = "骑手信息删除") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "骑手信息主键id集合(批量删除时id以逗号分隔)", required = true, paramType = "query", dataType = "String") - }) + @Operation(summary = "骑手信息删除") @DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) Rider rider){ BasicResult basicResult = new BasicResult(); - //获取当前登录用户绑定的门店编号 Merchant loginMerchant = merchantSessionManager.getSession(TokenUtil.getToken()); for (Integer id : rider.getIds()) { @@ -144,4 +109,4 @@ public BasicResult delete(@RequestBody @Validated(value = {}) Rider rider){ basicResult.setMessage("删除成功"); return basicResult; } -} \ No newline at end of file +} diff --git a/siam-rider/rider-provider/src/main/resources/application-local.yml b/siam-rider/rider-provider/src/main/resources/application-local.yml index c8256d2..73f1074 100644 --- a/siam-rider/rider-provider/src/main/resources/application-local.yml +++ b/siam-rider/rider-provider/src/main/resources/application-local.yml @@ -5,9 +5,9 @@ server: spring: #mysql datasource: - url: jdbc:mysql://127.0.0.1:3306/siam_cloud?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8 + url: jdbc:mysql://127.0.0.1:3306/siam_cloud?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true username: root - password: root + password: 123456 #redis单例模式 redis: @@ -31,6 +31,18 @@ spring: application: name: rider-siam + # Nacos注册中心/配置中心 + cloud: + nacos: + discovery: + server-addr: 127.0.0.1:8848 + config: + server-addr: 127.0.0.1:8848 + file-extension: yaml + config: + import: + - optional:nacos:${spring.application.name}-local.yaml + jackson: #时间戳统一转换为指定格式 date-format: yyyy/MM/dd HH:mm:ss @@ -90,17 +102,7 @@ mybatis-plus: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl -#eureka配置 -eureka: - client: - service-url: - defaultZone: http://127.0.0.1:9000/eureka/ - register-with-eureka: true - fetch-registry: true - instance: - #配置使用ip地址来注册(默认是主机名称) - prefer-ip-address: true - #心跳检测暂时不配置 +# Nacos注册中心/配置中心 #feign内部服务调用超时配置-第二种 feign: @@ -112,24 +114,31 @@ feign: # Seata Config seata: - application-id: rider-service + application-id: ${spring.application.name} tx-service-group: my_test_tx_group service: vgroup-mapping: - # 此处配置对应Server端配置registry.eureka.application的值 my_test_tx_group: default registry: - type: eureka - eureka: - service-url: http://127.0.0.1:9000/eureka/ - weight: 1 + type: nacos + nacos: + application: seata-server + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public + config: + type: nacos + nacos: + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public #springboot admin相关配置 management: endpoints: web: exposure: - include: "*" #'prometheus,health' + include: "health,prometheus,info" exclude: "shutdown" base-path: /actuator endpoint: @@ -154,6 +163,8 @@ management: enabled: false elasticsearch: enabled: false + mail: # 新增这行 + enabled: false # 新增这行 #日志配置 logging: diff --git a/siam-user/pom.xml b/siam-user/pom.xml index 3f34f44..8395b49 100644 --- a/siam-user/pom.xml +++ b/siam-user/pom.xml @@ -31,7 +31,5 @@ UTF-8 - 1.8 - 1.8 \ No newline at end of file diff --git a/siam-user/user-api/pom.xml b/siam-user/user-api/pom.xml index a7bd273..d8eded8 100644 --- a/siam-user/user-api/pom.xml +++ b/siam-user/user-api/pom.xml @@ -16,8 +16,6 @@ UTF-8 - 1.8 - 1.8 @@ -37,7 +35,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 exec diff --git a/siam-user/user-api/src/main/java/com/siam/package_user/entity/Admin.java b/siam-user/user-api/src/main/java/com/siam/package_user/entity/Admin.java index 6af3747..2321555 100644 --- a/siam-user/user-api/src/main/java/com/siam/package_user/entity/Admin.java +++ b/siam-user/user-api/src/main/java/com/siam/package_user/entity/Admin.java @@ -3,47 +3,46 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.Date; @Data @TableName("tb_admin") -@ApiModel(value = "管理员表") + @Schema(description= "管理员表") public class Admin { - @ApiModelProperty(notes = "主键id") + @Schema(description = "主键id") @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "管理员用户名") + @Schema(description = "管理员用户名") private String username; - @ApiModelProperty(notes = "手机号") + @Schema(description = "手机号") private String mobile; - @ApiModelProperty(notes = "密码") + @Schema(description = "密码") private String password; - @ApiModelProperty(notes = "密码盐值") + @Schema(description = "密码盐值") private String passwordSalt; - @ApiModelProperty(notes = "昵称") + @Schema(description = "昵称") private String nickname; - @ApiModelProperty(notes = "权限") + @Schema(description = "权限") private String roles; - @ApiModelProperty(notes = "是否禁用 0=启用 1=禁用") + @Schema(description = "是否禁用 0=启用 1=禁用") private Boolean isDisabled; - @ApiModelProperty(notes = "注册时间") + @Schema(description = "注册时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; - @ApiModelProperty(notes = "最后登录时间") + @Schema(description = "最后登录时间") private Date lastLoginTime; } \ No newline at end of file diff --git a/siam-user/user-api/src/main/java/com/siam/package_user/entity/AdminToken.java b/siam-user/user-api/src/main/java/com/siam/package_user/entity/AdminToken.java index a760a53..d092d39 100644 --- a/siam-user/user-api/src/main/java/com/siam/package_user/entity/AdminToken.java +++ b/siam-user/user-api/src/main/java/com/siam/package_user/entity/AdminToken.java @@ -1,30 +1,29 @@ package com.siam.package_user.entity; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Date; @TableName("tb_admin_token") -@ApiModel(value = "管理员登录token令牌表") + @Schema(description= "管理员登录token令牌表") public class AdminToken { - @ApiModelProperty(notes = "主键id") + @Schema(description = "主键id") private Integer id; - @ApiModelProperty(notes = "管理员id") + @Schema(description = "管理员id") private Integer adminId; - @ApiModelProperty(notes = "管理员用户名") + @Schema(description = "管理员用户名") private String username; - @ApiModelProperty(notes = "登录令牌") + @Schema(description = "登录令牌") private String token; - @ApiModelProperty(notes = "登录方式 wap") + @Schema(description = "登录方式 wap") private String type; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; public Integer getId() { diff --git a/siam-user/user-api/src/main/java/com/siam/package_user/entity/DeliveryAddress.java b/siam-user/user-api/src/main/java/com/siam/package_user/entity/DeliveryAddress.java index a41a01e..dd42077 100644 --- a/siam-user/user-api/src/main/java/com/siam/package_user/entity/DeliveryAddress.java +++ b/siam-user/user-api/src/main/java/com/siam/package_user/entity/DeliveryAddress.java @@ -3,8 +3,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; diff --git a/siam-user/user-api/src/main/java/com/siam/package_user/entity/MemberToken.java b/siam-user/user-api/src/main/java/com/siam/package_user/entity/MemberToken.java index c9dc6fd..311df01 100644 --- a/siam-user/user-api/src/main/java/com/siam/package_user/entity/MemberToken.java +++ b/siam-user/user-api/src/main/java/com/siam/package_user/entity/MemberToken.java @@ -3,32 +3,31 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Date; @TableName("tb_member_token") -@ApiModel(value = "用户登录token令牌表") + @Schema(description= "用户登录token令牌表") public class MemberToken { - @ApiModelProperty(notes = "主键id") + @Schema(description = "主键id") @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "用户id") + @Schema(description = "用户id") private Integer memberId; - @ApiModelProperty(notes = "用户名") + @Schema(description = "用户名") private String username; - @ApiModelProperty(notes = "登录令牌") + @Schema(description = "登录令牌") private String token; - @ApiModelProperty(notes = "登录方式 wap") + @Schema(description = "登录方式 wap") private String type; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; public Integer getId() { diff --git a/siam-user/user-api/src/main/java/com/siam/package_user/entity/MemberTradeRecord.java b/siam-user/user-api/src/main/java/com/siam/package_user/entity/MemberTradeRecord.java index bb238c2..8573164 100644 --- a/siam-user/user-api/src/main/java/com/siam/package_user/entity/MemberTradeRecord.java +++ b/siam-user/user-api/src/main/java/com/siam/package_user/entity/MemberTradeRecord.java @@ -3,8 +3,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import org.springframework.web.bind.annotation.RequestParam; @@ -13,7 +12,7 @@ @Data @TableName("tb_member_trade_record") -@ApiModel(value = "用户交易表") + @Schema(description= "用户交易表") public class MemberTradeRecord { @TableField(exist = false) @@ -22,38 +21,38 @@ public class MemberTradeRecord { @TableField(exist = false) Date endTime; - @ApiModelProperty(notes = "主键id") + @Schema(description = "主键id") @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "商家账号id") + @Schema(description = "商家账号id") private Integer merchantId; - @ApiModelProperty(notes = "用户id") + @Schema(description = "用户id") private Integer memberId; - @ApiModelProperty(notes = "交易单号(支付平台的订单号)") + @Schema(description = "交易单号(支付平台的订单号)") private String tradeNo; - @ApiModelProperty(notes = "商户单号(网站平台的订单号)") + @Schema(description = "商户单号(网站平台的订单号)") private String outTradeNo; - @ApiModelProperty(notes = "交易类型 1=用户订单付款 2=用户会员充值 3=用户自取订单改为配送 4=商家余额提现") + @Schema(description = "交易类型 1=用户订单付款 2=用户会员充值 3=用户自取订单改为配送 4=商家余额提现") private Integer type; - @ApiModelProperty(notes = "支付方式 1=微信 2=支付宝 3=平台余额 4=网银 5=银行转账") + @Schema(description = "支付方式 1=微信 2=支付宝 3=平台余额 4=网银 5=银行转账") private Integer paymentMode; - @ApiModelProperty(notes = "金额") + @Schema(description = "金额") private BigDecimal amount; - @ApiModelProperty(notes = "交易状态 1=待支付 2=支付成功 3=支付失败 3=交易超时自动关闭") + @Schema(description = "交易状态 1=待支付 2=支付成功 3=支付失败 3=交易超时自动关闭") private Integer status; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "修改时间") + @Schema(description = "修改时间") private Date updateTime; public Integer getId() { diff --git a/siam-user/user-api/src/main/java/com/siam/package_user/entity/internal/VipRechargeRecord.java b/siam-user/user-api/src/main/java/com/siam/package_user/entity/internal/VipRechargeRecord.java index 8e670da..651d749 100644 --- a/siam-user/user-api/src/main/java/com/siam/package_user/entity/internal/VipRechargeRecord.java +++ b/siam-user/user-api/src/main/java/com/siam/package_user/entity/internal/VipRechargeRecord.java @@ -4,8 +4,7 @@ import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; @@ -13,7 +12,7 @@ @Data @TableName("tb_vip_recharge_record") -@ApiModel(value = "会员充值记录表") + @Schema(description= "会员充值记录表") public class VipRechargeRecord { /* ##################################### START 扩展字段 #################################### */ diff --git a/siam-user/user-api/src/main/java/com/siam/package_user/jwt/AuthenticationInterceptor.java b/siam-user/user-api/src/main/java/com/siam/package_user/jwt/AuthenticationInterceptor.java index ef14c72..99029e6 100644 --- a/siam-user/user-api/src/main/java/com/siam/package_user/jwt/AuthenticationInterceptor.java +++ b/siam-user/user-api/src/main/java/com/siam/package_user/jwt/AuthenticationInterceptor.java @@ -11,8 +11,8 @@ //import org.springframework.web.method.HandlerMethod; //import org.springframework.web.servlet.HandlerInterceptor; //import org.springframework.web.servlet.ModelAndView; -//import javax.servlet.http.HttpServletRequest; -//import javax.servlet.http.HttpServletResponse; +//import jakarta.servlet.http.HttpServletRequest; +//import jakarta.servlet.http.HttpServletResponse; //import java.lang.reflect.Method; // //public class AuthenticationInterceptor implements HandlerInterceptor { diff --git a/siam-user/user-api/src/main/java/com/siam/package_user/model/param/MemberWithdrawRecordParam.java b/siam-user/user-api/src/main/java/com/siam/package_user/model/param/MemberWithdrawRecordParam.java index 2f65b42..cbac72d 100644 --- a/siam-user/user-api/src/main/java/com/siam/package_user/model/param/MemberWithdrawRecordParam.java +++ b/siam-user/user-api/src/main/java/com/siam/package_user/model/param/MemberWithdrawRecordParam.java @@ -6,7 +6,7 @@ import lombok.Data; import org.hibernate.validator.constraints.Range; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; import java.math.BigDecimal; import java.util.Date; diff --git a/siam-user/user-api/src/main/java/com/siam/package_user/util/HttpContext.java b/siam-user/user-api/src/main/java/com/siam/package_user/util/HttpContext.java index 8b603a7..33d93f7 100644 --- a/siam-user/user-api/src/main/java/com/siam/package_user/util/HttpContext.java +++ b/siam-user/user-api/src/main/java/com/siam/package_user/util/HttpContext.java @@ -3,8 +3,8 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.Map; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; diff --git a/siam-user/user-api/src/main/java/com/siam/package_user/util/TokenUtil.java b/siam-user/user-api/src/main/java/com/siam/package_user/util/TokenUtil.java index cdc52d9..b758979 100644 --- a/siam-user/user-api/src/main/java/com/siam/package_user/util/TokenUtil.java +++ b/siam-user/user-api/src/main/java/com/siam/package_user/util/TokenUtil.java @@ -10,9 +10,9 @@ import com.siam.package_user.entity.Admin; import com.siam.package_user.entity.Member; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.util.Date; /** diff --git a/siam-user/user-provider/pom.xml b/siam-user/user-provider/pom.xml index 9a4f275..b228ba0 100644 --- a/siam-user/user-provider/pom.xml +++ b/siam-user/user-provider/pom.xml @@ -16,8 +16,6 @@ UTF-8 - 1.8 - 1.8 @@ -63,51 +61,40 @@ 1.1 - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - 2.1.2.RELEASE - - - + com.alibaba.cloud - spring-cloud-starter-alibaba-seata - 2021.1 - - - io.seata - seata-spring-boot-starter - - + spring-cloud-starter-alibaba-nacos-discovery + - io.seata - seata-spring-boot-starter - 1.3.0 + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config org.springframework.boot spring-boot-starter-actuator - 2.3.3.RELEASE io.micrometer micrometer-registry-prometheus - 1.5.4 net.logstash.logback logstash-logback-encoder - 6.6 + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui @@ -117,7 +104,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 com.siam.package_user.UserApplication diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/UserApplication.java b/siam-user/user-provider/src/main/java/com/siam/package_user/UserApplication.java index 9375d9c..cfdf9e6 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/UserApplication.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/UserApplication.java @@ -1,15 +1,19 @@ package com.siam.package_user; -import org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @EnableFeignClients("com.siam") -@EnableEurekaClient -@SpringBootApplication(scanBasePackages = "com.siam", exclude = {RocketMQAutoConfiguration.class}) +@EnableDiscoveryClient +@SpringBootApplication(scanBasePackages = "com.siam", exclude = { + MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class +}) @MapperScan(basePackages = {"com.siam.**.mapper"}) public class UserApplication { diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/config/MybatisPlusConfig.java b/siam-user/user-provider/src/main/java/com/siam/package_user/config/MybatisPlusConfig.java index 910ef4e..5e1eb1c 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/config/MybatisPlusConfig.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/config/MybatisPlusConfig.java @@ -1,26 +1,23 @@ package com.siam.package_user.config; -import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MybatisPlusConfig { -// /** -// * mybatis-plus SQL执行效率插件【生产环境可以关闭】 -// */ -// @Bean -// public PerformanceInterceptor performanceInterceptor() { -// return new PerformanceInterceptor(); -// } - /** * 分页插件 */ @Bean - public PaginationInterceptor paginationInterceptor() { - return new PaginationInterceptor(); + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); + interceptor.addInnerInterceptor(paginationInnerInterceptor); + return interceptor; } - -} \ No newline at end of file + +} diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/config/Swagger2Config.java b/siam-user/user-provider/src/main/java/com/siam/package_user/config/Swagger2Config.java deleted file mode 100644 index 9032964..0000000 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/config/Swagger2Config.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.siam.package_user.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; - -@Configuration -@EnableSwagger2 -public class Swagger2Config { - - @Bean - public Docket createRestApi() { - return new Docket(DocumentationType.SWAGGER_2) - .apiInfo(apiInfo()) - .select() - .apis(RequestHandlerSelectors.basePackage("com.siam"))//扫描包路径 - .paths(PathSelectors.any()) - .build(); - } - - // 构建api文档的详细信息函数,注意这里的注解引用的是哪个 - private ApiInfo apiInfo() { - return new ApiInfoBuilder() - .title("暹罗外卖-用户服务接口文档")//页面标题 - .description("")//描述 - .version("1.0")//版本号 - .build(); - } -} \ No newline at end of file diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminController.java b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminController.java index 0ee2241..29bda44 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminController.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminController.java @@ -6,7 +6,8 @@ import com.siam.package_user.model.param.AdminParam; import com.siam.package_user.model.result.AdminResult; import com.siam.package_user.service.AdminService; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -15,7 +16,7 @@ @RestController @RequestMapping(value = "/rest/admin") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台管理员模块相关接口", description = "AdminController") +@Tag(name = "后台管理员模块相关接口", description = "AdminController") public class AdminController { @Autowired diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminDeliveryAddressController.java b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminDeliveryAddressController.java index 28160b7..75854ab 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminDeliveryAddressController.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminDeliveryAddressController.java @@ -6,8 +6,9 @@ import com.siam.package_common.entity.BasicResult; import com.siam.package_user.entity.DeliveryAddress; import com.siam.package_user.service.DeliveryAddressService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -19,13 +20,13 @@ @RestController @RequestMapping(value = "/rest/admin/deliveryAddress") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台收货地址模块相关接口", description = "AdminDeliveryAddressController") +@Tag(name = "后台收货地址模块相关接口", description = "AdminDeliveryAddressController") public class AdminDeliveryAddressController { @Autowired private DeliveryAddressService deliveryAddressService; - @ApiOperation(value = "收货地址列表") + @Operation(summary = "收货地址列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) DeliveryAddress param) { BasicData basicResult = new BasicData(); @@ -35,7 +36,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) DeliveryAddress para return BasicResult.success(page); } - @ApiOperation(value = "新增收货地址") + @Operation(summary = "新增收货地址") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) DeliveryAddress param) { BasicResult basicResult = new BasicResult(); @@ -48,7 +49,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) DeliveryAddress pa return basicResult; } - @ApiOperation(value = "修改收货地址") + @Operation(summary = "修改收货地址") @PostMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) DeliveryAddress param) { BasicResult basicResult = new BasicResult(); @@ -61,7 +62,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) DeliveryAddress pa return basicResult; } - @ApiOperation(value = "删除收货地址") + @Operation(summary = "删除收货地址") @PostMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) DeliveryAddress param) { BasicResult basicResult = new BasicResult(); diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminMemberBillingRecordController.java b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminMemberBillingRecordController.java index ebfd74e..487519b 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminMemberBillingRecordController.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminMemberBillingRecordController.java @@ -6,10 +6,26 @@ //import com.siam.package_common.constant.BasicResultCode; //import com.siam.package_user.entity.MemberBillingRecord; //import com.siam.package_user.service.MemberBillingRecordService; -//import io.swagger.annotations.Api; -//import io.swagger.annotations.ApiImplicitParam; -//import io.swagger.annotations.ApiImplicitParams; -//import io.swagger.annotations.ApiOperation; +//import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +//import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +//import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +//import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; //import org.springframework.beans.factory.annotation.Autowired; //import org.springframework.transaction.annotation.Transactional; //import org.springframework.web.bind.annotation.PostMapping; @@ -19,23 +35,14 @@ //@RestController //@RequestMapping(value = "/rest/admin/memberBillingRecord") //@Transactional(rollbackFor = Exception.class) -//@Api(tags = "后台用户账单记录模块相关接口", description = "AdminMemberBillingRecordController") +//@Tag(name = "后台用户账单记录模块相关接口", description = "AdminMemberBillingRecordController") //public class AdminMemberBillingRecordController { // // @Autowired // private MemberBillingRecordService memberBillingRecordService; // -// @ApiOperation(value = "用户账单记录列表") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "id", value = "商品表主键id", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "name", value = "商品名称", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "detail", value = "用户账单记录详情描述", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), -// @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") -// }) -// @PostMapping(value = "/list") +// @Operation(summary = "用户账单记录列表") +//// @PostMapping(value = "/list") // public BasicResult list(int pageNo, int pageSize, MemberBillingRecord memberBillingRecord){ // BasicData basicResult = new BasicData(); // Page page = memberBillingRecordService.getListByPage(param.getPageNo(), param.getPageSize(), memberBillingRecord); @@ -47,15 +54,8 @@ // return basicResult; // } // -// @ApiOperation(value = "用户账单记录创建") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "id", value = "用户账单记录主键id", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "name", value = "用户账单记录名称", required = true, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "detail", value = "用户账单记录详情描述", required = false, paramType = "query", dataType = "string") -// }) -// @PostMapping(value = "/insert") +// @Operation(summary = "用户账单记录创建") +//// @PostMapping(value = "/insert") // public BasicResult insert(MemberBillingRecord memberBillingRecord){ // BasicResult basicResult = new BasicResult(); // diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminMemberController.java b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminMemberController.java index 84aa08f..2ebee66 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminMemberController.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminMemberController.java @@ -6,8 +6,11 @@ import com.siam.package_user.entity.Member; import com.siam.package_user.model.param.MemberParam; import com.siam.package_user.service.MemberService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -19,27 +22,27 @@ @RestController @RequestMapping(value = "/rest/admin/member") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台用户模块相关接口", description = "AdminMemberController") +@Tag(name = "后台用户模块相关接口", description = "AdminMemberController") public class AdminMemberController { @Autowired private MemberService memberService; - @ApiOperation(value = "用户列表") + @Operation(summary = "用户列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) MemberParam param) { Page page = memberService.getListByPage(param); return BasicResult.success(page); } - @ApiOperation(value = "查询已购买用户列表") + @Operation(summary = "查询已购买用户列表") @PostMapping(value = "/purchasedList") public BasicResult purchasedList(@RequestBody @Validated(value = {}) MemberParam param) { Page page = memberService.purchasedList(param); return BasicResult.success(page); } - @ApiOperation(value = "查询未购买用户列表") + @Operation(summary = "查询未购买用户列表") @PostMapping(value = "/unPurchasedList") public BasicResult unPurchasedList(@RequestBody @Validated(value = {}) MemberParam param) { Page page = memberService.unPurchasedList(param); @@ -47,7 +50,7 @@ public BasicResult unPurchasedList(@RequestBody @Validated(value = {}) MemberPar } @AdminPermission - @ApiOperation(value = "修改用户信息") + @Operation(summary = "修改用户信息") @PostMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) MemberParam param) { //管理员只准修改个别字段信息 @@ -58,11 +61,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) MemberParam param) return BasicResult.success(); } - /*@ApiOperation(value = "启用用户(含批量操作)") - @ApiImplicitParams({ - @ApiImplicitParam(name = "ids", value = "用户表主键id(批量启用时id以逗号分隔)", required = true, paramType = "query", dataType = "string"), - }) - @PostMapping(value = "/enable") + /*@Operation(summary = "启用用户(含批量操作)")@PostMapping(value = "/enable") public BasicResult enable(@RequestParam(value = "ids", required = true) List ids){ BasicResult basicResult = new BasicResult(); @@ -96,11 +95,7 @@ public BasicResult enable(@RequestParam(value = "ids", required = true) List ids){ BasicResult basicResult = new BasicResult(); @@ -134,11 +129,7 @@ public BasicResult disable(@RequestParam(value = "ids", required = true) List ids){ BasicResult basicResult = new BasicResult(); diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminMemberTradeRecordController.java b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminMemberTradeRecordController.java index 223f3ad..a70e6a5 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminMemberTradeRecordController.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminMemberTradeRecordController.java @@ -6,10 +6,26 @@ //import com.siam.package_common.constant.BasicResultCode; //import com.siam.package_user.entity.MemberTradeRecord; //import com.siam.package_user.service.MemberTradeRecordService; -//import io.swagger.annotations.Api; -//import io.swagger.annotations.ApiImplicitParam; -//import io.swagger.annotations.ApiImplicitParams; -//import io.swagger.annotations.ApiOperation; +//import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +//import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +//import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +//import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; //import org.springframework.beans.factory.annotation.Autowired; //import org.springframework.transaction.annotation.Transactional; //import org.springframework.web.bind.annotation.PostMapping; @@ -22,24 +38,13 @@ //@RestController //@RequestMapping(value = "/rest/admin/memberTrade") //@Transactional(rollbackFor = Exception.class) -//@Api(tags = "后台用户交易模块相关接口", description = "AdminMemberTradeController") +//@Tag(name = "后台用户交易模块相关接口", description = "AdminMemberTradeController") //public class AdminMemberTradeRecordController { // @Autowired // private MemberTradeRecordService memberTradeRecordService; // -// @ApiOperation(value = "用户交易列表") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "id", value = "用户交易表主键id", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "name", value = "用户交易名称", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "logo", value = "logo图片", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "firstLetter", value = "用户交易首字母", required = false, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "parentId", value = "父类别id", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "sortNumber", value = "排序号", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), -// @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), -// }) -// @PostMapping(value = "/list") +// @Operation(summary = "用户交易列表") +//// @PostMapping(value = "/list") // public BasicResult list(int pageNo, int pageSize, MemberTradeRecord memberTradeRecord){ // BasicData basicResult = new BasicData(); // @@ -53,16 +58,8 @@ // } // // -// @ApiOperation(value = "新增用户交易") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "name", value = "用户交易名称", required = true, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "logo", value = "logo图片", required = true, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "firstLetter", value = "用户交易首字母", required = true, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "parentId", value = "父类别id", required = true, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "sortNumber", value = "排序号", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), -// }) -// @PostMapping(value = "/insert") +// @Operation(summary = "新增用户交易") +//// @PostMapping(value = "/insert") // public BasicResult insert(MemberTradeRecord memberTradeRecord){ // BasicResult basicResult = new BasicResult(); // @@ -74,17 +71,8 @@ // return basicResult; // } // -// @ApiOperation(value = "修改用户交易") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "id", value = "用户交易表主键id", required = true, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "name", value = "用户交易名称", required = true, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "logo", value = "logo图片", required = true, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "firstLetter", value = "用户交易首字母", required = true, paramType = "query", dataType = "string"), -// @ApiImplicitParam(name = "parentId", value = "父类别id", required = true, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "sortNumber", value = "排序号", required = false, paramType = "query", dataType = "int"), -// @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), -// }) -// @PostMapping(value = "/update") +// @Operation(summary = "修改用户交易") +//// @PostMapping(value = "/update") // public BasicResult update(MemberTradeRecord memberTradeRecord){ // BasicResult basicResult = new BasicResult(); // @@ -96,11 +84,8 @@ // return basicResult; // } // -// @ApiOperation(value = "删除用户交易(含批量操作)") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "ids", value = "用户交易表主键id(批量删除时id以逗号分隔)", required = true, paramType = "query", dataType = "string"), -// }) -// @PostMapping(value = "/delete") +// @Operation(summary = "删除用户交易(含批量操作)") +//// @PostMapping(value = "/delete") // public BasicResult delete(@RequestParam(value = "ids", required = true) List ids){ // BasicResult basicResult = new BasicResult(); // diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminMemberWithdrawRecordController.java b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminMemberWithdrawRecordController.java index d865974..b6585f4 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminMemberWithdrawRecordController.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/AdminMemberWithdrawRecordController.java @@ -6,8 +6,9 @@ import com.siam.package_common.model.valid_group.ValidGroupOfId; import com.siam.package_user.model.param.MemberWithdrawRecordParam; import com.siam.package_user.service.MemberWithdrawRecordService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -21,20 +22,20 @@ @RestController @RequestMapping(value = "/rest/admin/memberWithdrawRecord") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台用户提现记录模块相关接口", description = "AdminMemberWithdrawRecordController") +@Tag(name = "后台用户提现记录模块相关接口", description = "AdminMemberWithdrawRecordController") public class AdminMemberWithdrawRecordController { @Autowired private MemberWithdrawRecordService memberWithdrawRecordService; - @ApiOperation(value = "用户提现记录列表") + @Operation(summary = "用户提现记录列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) MemberWithdrawRecordParam param) { Page> page = memberWithdrawRecordService.getListByPageJoinMember(param); return BasicResult.success(page); } - @ApiOperation(value = "用户提现记录-统计金额") + @Operation(summary = "用户提现记录-统计金额") @PostMapping(value = "/statisticalAmount") public BasicResult statisticalAmount(@RequestBody @Validated(value = {}) MemberWithdrawRecordParam param) { Map map = memberWithdrawRecordService.statisticalAmount(param); diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/internal/AdminVipRechargeDenominationController.java b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/internal/AdminVipRechargeDenominationController.java index 2829291..a3a5e97 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/internal/AdminVipRechargeDenominationController.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/internal/AdminVipRechargeDenominationController.java @@ -8,8 +8,9 @@ import com.siam.package_common.entity.BasicResult; import com.siam.package_common.constant.BasicResultCode; import com.siam.package_user.entity.internal.VipRechargeDenomination; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -20,7 +21,7 @@ @RestController @RequestMapping(value = "/rest/admin/vipRechargeDenomination") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台会员充值面额模块相关接口", description = "AdminVipRechargeDenominationController") +@Tag(name = "后台会员充值面额模块相关接口", description = "AdminVipRechargeDenominationController") public class AdminVipRechargeDenominationController { @Autowired @@ -29,7 +30,7 @@ public class AdminVipRechargeDenominationController { @Autowired private VipRechargeDenominationCouponsRelationService vipRechargeDenominationCouponsRelationService; - @ApiOperation(value = "会员充值面额列表") + @Operation(summary = "会员充值面额列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) VipRechargeDenomination vipRechargeDenomination){ BasicData basicResult = new BasicData(); @@ -38,7 +39,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) VipRechargeDenominat return BasicResult.success(page); } - @ApiOperation(value = "新增会员充值面额") + @Operation(summary = "新增会员充值面额") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) VipRechargeDenomination vipRechargeDenomination){ BasicResult basicResult = new BasicResult(); @@ -54,7 +55,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) VipRechargeDenomin } @AdminPermission - @ApiOperation(value = "修改会员充值面额") + @Operation(summary = "修改会员充值面额") @PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) VipRechargeDenomination vipRechargeDenomination){ BasicResult basicResult = new BasicResult(); @@ -69,7 +70,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) VipRechargeDenomin } @AdminPermission - @ApiOperation(value = "删除会员充值面额") + @Operation(summary = "删除会员充值面额") @DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) VipRechargeDenomination param){ BasicResult basicResult = new BasicResult(); diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/internal/AdminVipRechargeDenominationCouponsRelationController.java b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/internal/AdminVipRechargeDenominationCouponsRelationController.java index f12d481..07b638c 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/internal/AdminVipRechargeDenominationCouponsRelationController.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/internal/AdminVipRechargeDenominationCouponsRelationController.java @@ -7,8 +7,9 @@ import com.siam.package_common.constant.BasicResultCode; import com.siam.package_common.util.GsonUtils; import com.siam.package_user.entity.internal.VipRechargeDenominationCouponsRelation; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -19,13 +20,13 @@ @RestController @RequestMapping(value = "/rest/admin/vipRechargeDenominationCouponsRelation") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台会员充值面额与赠送优惠券关联接口", description = "AdminCouponsController") +@Tag(name = "后台会员充值面额与赠送优惠券关联接口", description = "AdminCouponsController") public class AdminVipRechargeDenominationCouponsRelationController { @Autowired private VipRechargeDenominationCouponsRelationService vipRechargeDenominationCouponsRelationService; - @ApiOperation(value = "新增会员充值面额与赠送优惠券关联") + @Operation(summary = "新增会员充值面额与赠送优惠券关联") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) VipRechargeDenominationCouponsRelation param) { BasicResult basicResult = new BasicResult(); @@ -39,7 +40,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) VipRechargeDenomin return basicResult; } - @ApiOperation(value = "会员充值面额与赠送优惠券关联列表查询") + @Operation(summary = "会员充值面额与赠送优惠券关联列表查询") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) VipRechargeDenominationCouponsRelation vipRechargeDenominationCouponsRelation) { BasicData basicResult = new BasicData(); diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/internal/AdminVipRechargeRecordController.java b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/internal/AdminVipRechargeRecordController.java index 8207d9d..3560c97 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/internal/AdminVipRechargeRecordController.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/admin/internal/AdminVipRechargeRecordController.java @@ -9,16 +9,17 @@ import com.siam.package_user.entity.internal.VipRechargeRecord; import com.siam.package_user.service.internal.VipRechargeRecordService; import com.siam.package_user.entity.Member; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang.time.DateUtils; +import org.apache.commons.lang3.time.DateUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.Date; import java.util.Map; @@ -26,7 +27,7 @@ @RestController @RequestMapping(value = "/rest/admin/vipRechargeRecord") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台会员充值记录模块相关接口", description = "AdminVipRechargeRecordController") +@Tag(name = "后台会员充值记录模块相关接口", description = "AdminVipRechargeRecordController") public class AdminVipRechargeRecordController { @Autowired @@ -35,7 +36,7 @@ public class AdminVipRechargeRecordController { @Autowired private MemberFeignApi memberFeignApi; - @ApiOperation(value = "会员充值记录列表") + @Operation(summary = "会员充值记录列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) VipRechargeRecord vipRechargeRecord){ BasicData basicResult = new BasicData(); @@ -46,7 +47,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) VipRechargeRecord vi return BasicResult.success(page); } - @ApiOperation(value = "会员充值记录-统计金额") + @Operation(summary = "会员充值记录-统计金额") @PostMapping(value = "/statisticalAmount") public BasicResult statisticalAmount(@RequestBody @Validated(value = {}) VipRechargeRecord vipRechargeRecord, HttpServletRequest request){ BasicData basicResult = new BasicData(); @@ -60,7 +61,7 @@ public BasicResult statisticalAmount(@RequestBody @Validated(value = {}) VipRech return basicResult; } - @ApiOperation(value = "后台管理员充值会员") + @Operation(summary = "后台管理员充值会员") @PostMapping(value = "/updateVip") public BasicResult update(@RequestBody @Validated(value = {}) VipRechargeRecord vipRechargeRecord){ log.info("请求参数 -> " + vipRechargeRecord); @@ -113,7 +114,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) VipRechargeRecord return basicResult; } -// @ApiOperation(value = "会员充值记录创建") +// @Operation(summary = "会员充值记录创建") // @PostMapping(value = "/insert") // public BasicResult insert(VipRechargeRecord vipRechargeRecord){ // BasicResult basicResult = new BasicResult(); diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/DeliveryAddressController.java b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/DeliveryAddressController.java index 0f9dce0..4066574 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/DeliveryAddressController.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/DeliveryAddressController.java @@ -10,22 +10,21 @@ import com.siam.package_user.auth.cache.MemberSessionManager; import com.siam.package_user.entity.Member; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.Date; @RestController @RequestMapping(value = "/rest/member/deliveryAddress") @Transactional(rollbackFor = Exception.class) -@Api(tags = "收货地址模块相关接口", description = "DeliveryAddressController") +@Tag(name = "收货地址模块相关接口", description = "DeliveryAddressController") public class DeliveryAddressController { @Autowired @@ -34,19 +33,7 @@ public class DeliveryAddressController { @Autowired private MemberSessionManager memberSessionManager; - @ApiOperation(value = "收货地址列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "收货地址表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "realname", value = "收件人姓名", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "phone", value = "联系电话", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sex", value = "收件人性别 0=男 1=女", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "area", value = "地区(收货地址)", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "street", value = "街道/详细收货地址", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "isDefault", value = "是否默认收获地址 0=否 1=是", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否禁用 0=启用 1=禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) + @Operation(summary = "收货地址列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) DeliveryAddress deliveryAddress, HttpServletRequest request){ BasicData basicResult = new BasicData(); @@ -55,46 +42,20 @@ public BasicResult list(@RequestBody @Validated(value = {}) DeliveryAddress deli deliveryAddress.setMemberId(loginMember.getId()); Page page = deliveryAddressService.getListByPage(deliveryAddress.getPageNo(), deliveryAddress.getPageSize(), deliveryAddress); - // 对手机号码做加密处理 (从这种list中修改数据时,我体会到了按址传递和按值传递的意义所在) - /*List list = page.getRecords(); - list.forEach(address -> { - String phone = address.getPhone(); - if(phone.length() == 11){ - phone = phone.substring(0, 3) + "*****" + phone.substring(phone.length()-3); - address.setPhone(phone); - } - });*/ - return BasicResult.success(page); } - @ApiOperation(value = "新增收货地址") - @ApiImplicitParams({ - @ApiImplicitParam(name = "memberId", value = "用户id", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "realname", value = "收件人姓名", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sex", value = "收件人性别 0=男 1=女", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "phone", value = "联系电话", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "province", value = "省份(收货地址)", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "city", value = "市区(收货地址)", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "area", value = "地区(收货地址)", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "street", value = "街道/详细收货地址", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "isDefault", value = "是否默认收获地址 0=否 1=是", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否禁用 0=启用 1=禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDeleted", value = "是否删除 0=正常 1=已删除", required = false, paramType = "query", dataType = "int") - - }) + @Operation(summary = "新增收货地址") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) DeliveryAddress deliveryAddress, HttpServletRequest request){ BasicData basicResult = new BasicData(); Member loginMember = memberSessionManager.getSession(TokenUtil.getToken()); - // 添加DeliveryAddress数据 deliveryAddress.setMemberId(loginMember.getId()); deliveryAddress.setCreateTime(new Date()); deliveryAddress.setUpdateTime(new Date()); deliveryAddressService.insertSelective(deliveryAddress); - //将不等于当前这个地址,这个用户下其他的地址默认设置为否 if(deliveryAddress.getIsDefault() == Quantity.INT_1){ deliveryAddressService.updateIsDefaultExclusion(deliveryAddress.getId(), deliveryAddress.getMemberId()); } @@ -106,19 +67,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) DeliveryAddress de return basicResult; } - @ApiOperation(value = "修改收货地址") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "收货地址表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "realname", value = "收件人姓名", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "phone", value = "联系电话", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sex", value = "收件人性别 0=男 1=女", required = true, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "province", value = "省份(收货地址)", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "city", value = "市区(收货地址)", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "area", value = "地区(收货地址)", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "street", value = "街道/详细收货地址", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "isDisabled", value = "是否禁用 0=启用 1=禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDefault", value = "是否默认收获地址 0=否 1=是", required = true, paramType = "query", dataType = "int") - }) + @Operation(summary = "修改收货地址") @PostMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) DeliveryAddress deliveryAddress, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); @@ -139,11 +88,9 @@ public BasicResult update(@RequestBody @Validated(value = {}) DeliveryAddress de return basicResult; } - // 更新DeliveryAddress数据 deliveryAddress.setUpdateTime(new Date()); deliveryAddressService.updateByPrimaryKeySelective(deliveryAddress); - //将不等于当前这个地址,这个用户下其他的地址默认设置为否 if(deliveryAddress.getIsDefault() == Quantity.INT_1){ deliveryAddressService.updateIsDefaultExclusion(dbDeliveryAddress.getId(), dbDeliveryAddress.getMemberId()); } @@ -155,10 +102,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) DeliveryAddress de } - @ApiOperation(value = "删除收货地址") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "收货地址表主键id", required = false, paramType = "query", dataType = "int") - }) + @Operation(summary = "删除收货地址") @PostMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) DeliveryAddress param){ BasicResult basicResult = new BasicResult(); @@ -179,7 +123,6 @@ public BasicResult delete(@RequestBody @Validated(value = {}) DeliveryAddress pa return basicResult; } - //删除DeliveryAddress数据 deliveryAddressService.deleteByPrimaryKey(param.getId()); basicResult.setSuccess(true); @@ -189,10 +132,7 @@ public BasicResult delete(@RequestBody @Validated(value = {}) DeliveryAddress pa } - @ApiOperation(value = "设为默认收货地址") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "收货地址表主键id", required = false, paramType = "query", dataType = "int") - }) + @Operation(summary = "设为默认收货地址") @PostMapping(value = "/updateIsDefault") public BasicResult updateIsDefault(@RequestBody @Validated(value = {}) DeliveryAddress param){ BasicResult basicResult = new BasicResult(); @@ -213,13 +153,11 @@ public BasicResult updateIsDefault(@RequestBody @Validated(value = {}) DeliveryA return basicResult; } - // 更新DeliveryAddress数据 DeliveryAddress updateDeliveryAddress = new DeliveryAddress(); updateDeliveryAddress.setId(dbDeliveryAddress.getId()); updateDeliveryAddress.setIsDefault(Quantity.INT_1); deliveryAddressService.updateByPrimaryKeySelective(updateDeliveryAddress); - //将不等于当前这个地址,这个用户下其他的地址默认设置为否 deliveryAddressService.updateIsDefaultExclusion(dbDeliveryAddress.getId(), dbDeliveryAddress.getMemberId()); basicResult.setSuccess(true); @@ -227,4 +165,4 @@ public BasicResult updateIsDefault(@RequestBody @Validated(value = {}) DeliveryA basicResult.setMessage("设置成功"); return basicResult; } -} \ No newline at end of file +} diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/MemberController.java b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/MemberController.java index 449cec1..f924e4b 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/MemberController.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/MemberController.java @@ -4,7 +4,8 @@ import com.siam.package_user.model.param.MemberParam; import com.siam.package_user.model.result.MemberResult; import com.siam.package_user.service.MemberService; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -186,7 +187,7 @@ public BasicResult forgetPaymentPasswordStep2(@RequestBody @Validated(value = {} * @author 暹罗 */ @RequestMapping(value = "/verifyPaymentPassword",method = RequestMethod.POST) - @ApiOperation(value = "") + @Operation(summary = "") public BasicResult verifyPaymentPassword(@RequestBody @Validated(value = {}) MemberParam param) { memberService.verifyPaymentPassword(param); return BasicResult.success(); diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/MemberInviteRelationController.java b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/MemberInviteRelationController.java index 389e9c4..3c11a51 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/MemberInviteRelationController.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/MemberInviteRelationController.java @@ -6,8 +6,11 @@ import com.siam.package_user.entity.Member; import com.siam.package_user.model.param.MemberInviteRelationParam; import com.siam.package_user.service.MemberInviteRelationService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -18,25 +21,20 @@ @RestController @RequestMapping(value = "/rest/memberInviteRelation") @Transactional(rollbackFor = Exception.class) -@Api(tags = "用户邀请关系模块相关接口", description = "MemberInviteRelationController") +@Tag(name = "用户邀请关系模块相关接口", description = "MemberInviteRelationController") public class MemberInviteRelationController { @Autowired private MemberInviteRelationService memberInviteRelationService; - @ApiOperation(value = "通过邀请者id获取邀请的用户") + @Operation(summary = "通过邀请者id获取邀请的用户") @PostMapping(value = "/getMemberListByInviterId") public BasicResult getUserListByInviterId(@RequestBody @Validated(value = {}) MemberInviteRelationParam param) { Page result = memberInviteRelationService.getMemberListByInviterId(param); return BasicResult.success(result); } - /*@ApiOperation(value = "新用户被邀请接口") - @ApiImplicitParams({ - @ApiImplicitParam(name = "mobile", value = "用户手机号", required = true, paramType = "query", dataType = "int", defaultValue = "null"), - @ApiImplicitParam(name = "inviterId", value = "邀请者id", required = true, paramType = "query", dataType = "int", defaultValue = "null") - }) - @PostMapping(value = "/newMemberInvite") + /*@Operation(summary = "新用户被邀请接口")@PostMapping(value = "/newMemberInvite") public BasicResult getLoginMemberInfo(@RequestParam String mobile,@RequestParam Integer inviterId) { BasicResult basicResult = new BasicResult(); diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/MemberTradeRecordController.java b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/MemberTradeRecordController.java index 752ecf7..5cf57b1 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/MemberTradeRecordController.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/MemberTradeRecordController.java @@ -1,7 +1,11 @@ package com.siam.package_user.controller.member; import com.siam.package_user.service.MemberTradeRecordService; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RequestMapping; @@ -10,24 +14,12 @@ @RestController @RequestMapping(value = "/rest/memberTrade") @Transactional(rollbackFor = Exception.class) -@Api(tags = "用户交易模块相关接口", description = "MemberTradeController") +@Tag(name = "用户交易模块相关接口", description = "MemberTradeController") public class MemberTradeRecordController { @Autowired private MemberTradeRecordService memberTradeRecordService; - /*@ApiOperation(value = "用户交易列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "用户交易表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "用户交易名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "logo", value = "logo图片", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "firstLetter", value = "用户交易首字母", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "parentId", value = "父类别id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "sortNumber", value = "排序号", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "status", value = "状态 1=启用 0=禁用 -1=删除", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) - @PostMapping(value = "/list") + /*@Operation(summary = "用户交易列表")@PostMapping(value = "/list") public BasicResult list(int pageNo, int pageSize, MemberTradeRecord memberTradeRecord){ BasicData basicResult = new BasicData(); diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/MemberWithdrawRecordController.java b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/MemberWithdrawRecordController.java index 2243803..38e6fe6 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/MemberWithdrawRecordController.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/MemberWithdrawRecordController.java @@ -5,8 +5,9 @@ import com.siam.package_user.entity.MemberWithdrawRecord; import com.siam.package_user.model.param.MemberWithdrawRecordParam; import com.siam.package_user.service.MemberWithdrawRecordService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -17,20 +18,20 @@ @RestController @RequestMapping(value = "/rest/member/memberWithdrawRecord") @Transactional(rollbackFor = Exception.class) -@Api(tags = "用户提现记录模块相关接口", description = "MemberWithdrawRecordController") +@Tag(name = "用户提现记录模块相关接口", description = "MemberWithdrawRecordController") public class MemberWithdrawRecordController { @Autowired private MemberWithdrawRecordService memberWithdrawRecordService; - @ApiOperation(value = "用户提现记录列表") + @Operation(summary = "用户提现记录列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) MemberWithdrawRecordParam param) { Page page = memberWithdrawRecordService.getListByPage(param); return BasicResult.success(page); } - @ApiOperation(value = "邀请新用户注册奖励金额-用户提现接口") + @Operation(summary = "邀请新用户注册奖励金额-用户提现接口") @PostMapping(value = "/inviteRewardAmount/insert") public BasicResult insert(@RequestBody @Validated(value = {}) MemberWithdrawRecordParam param) { memberWithdrawRecordService.insert(param); diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/WxLoginController.java b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/WxLoginController.java index a27666f..7b6b748 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/WxLoginController.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/WxLoginController.java @@ -8,7 +8,8 @@ import com.siam.package_weixin_basic.config.WxEncrypted; import com.siam.package_weixin_basic.config.WxSession; import com.siam.package_weixin_basic.util.WxdecodeUtils; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.http.HttpMethod; @@ -90,7 +91,7 @@ public WxEncrypted getWxUserInfo(String code, String iv, String encryptedData) t return null; } - @ApiOperation(value = "获取微信手机号") + @Operation(summary = "获取微信手机号") @PostMapping(value = "/getWxPhone") public BasicResult getWxPhone(@RequestBody WxCode wxCode) throws Exception { BasicData basicResult = new BasicData(); diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/internal/VipRechargeDenominationController.java b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/internal/VipRechargeDenominationController.java index 4774d89..5c41074 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/internal/VipRechargeDenominationController.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/internal/VipRechargeDenominationController.java @@ -5,8 +5,9 @@ import com.siam.package_common.entity.BasicData; import com.siam.package_common.entity.BasicResult; import com.siam.package_user.entity.internal.VipRechargeDenomination; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -18,13 +19,13 @@ @RestController @RequestMapping(value = "/rest/vipRechargeDenomination") @Transactional(rollbackFor = Exception.class) -@Api(tags = "会员充值面额模块相关接口", description = "VipRechargeDenominationController") +@Tag(name = "会员充值面额模块相关接口", description = "VipRechargeDenominationController") public class VipRechargeDenominationController { @Autowired private VipRechargeDenominationService vipRechargeDenominationService; - @ApiOperation(value = "会员充值面额列表") + @Operation(summary = "会员充值面额列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) VipRechargeDenomination vipRechargeDenomination){ BasicData basicResult = new BasicData(); diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/internal/VipRechargeRecordController.java b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/internal/VipRechargeRecordController.java index ee43189..a36c029 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/internal/VipRechargeRecordController.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/controller/member/internal/VipRechargeRecordController.java @@ -11,8 +11,9 @@ import com.siam.package_user.entity.internal.VipRechargeRecord; import com.siam.package_user.service.internal.VipRechargeRecordService; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -22,13 +23,13 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; @Slf4j @RestController @RequestMapping(value = "/rest/member/vipRechargeRecord") @Transactional(rollbackFor = Exception.class) -@Api(tags = "会员充值记录模块相关接口", description = "VipRechargeRecordController") +@Tag(name = "会员充值记录模块相关接口", description = "VipRechargeRecordController") public class VipRechargeRecordController { @Autowired @@ -37,7 +38,7 @@ public class VipRechargeRecordController { @Autowired private MemberSessionManager memberSessionManager; - @ApiOperation(value = "会员充值记录列表") + @Operation(summary = "会员充值记录列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) VipRechargeRecord vipRechargeRecord, HttpServletRequest request){ BasicData basicResult = new BasicData(); @@ -51,7 +52,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) VipRechargeRecord vi return BasicResult.success(page); } - @ApiOperation(value = "查看会员充值记录详情") + @Operation(summary = "查看会员充值记录详情") @PostMapping(value = "/detail") public BasicResult detail(@RequestBody @Validated(value = {}) VipRechargeRecord vipRechargeRecord, HttpServletRequest request){ BasicData basicResult = new BasicData(); diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/service_impl/MemberBillingRecordServiceImpl.java b/siam-user/user-provider/src/main/java/com/siam/package_user/service_impl/MemberBillingRecordServiceImpl.java index 5e2e234..f4a8577 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/service_impl/MemberBillingRecordServiceImpl.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/service_impl/MemberBillingRecordServiceImpl.java @@ -13,6 +13,7 @@ import com.siam.package_user.service.MemberService; import com.siam.package_user.util.TokenUtil; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import java.math.BigDecimal; @@ -26,6 +27,7 @@ public class MemberBillingRecordServiceImpl implements MemberBillingRecordServic @Autowired private MemberBillingRecordMapper memberBillingRecordMapper; + @Lazy @Autowired private MemberService memberService; diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/service_impl/MemberInviteRelationServiceImpl.java b/siam-user/user-provider/src/main/java/com/siam/package_user/service_impl/MemberInviteRelationServiceImpl.java index b5c01e8..aadc0b6 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/service_impl/MemberInviteRelationServiceImpl.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/service_impl/MemberInviteRelationServiceImpl.java @@ -14,6 +14,7 @@ import com.siam.package_user.service.MemberTokenService; import com.siam.package_user.util.TokenUtil; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import java.util.Date; @@ -31,6 +32,7 @@ public class MemberInviteRelationServiceImpl implements MemberInviteRelationServ @Autowired private MemberMapper memberMapper; + @Lazy @Autowired private MemberService memberService; diff --git a/siam-user/user-provider/src/main/java/com/siam/package_user/service_impl/MemberServiceImpl.java b/siam-user/user-provider/src/main/java/com/siam/package_user/service_impl/MemberServiceImpl.java index 4721852..f3fc35f 100644 --- a/siam-user/user-provider/src/main/java/com/siam/package_user/service_impl/MemberServiceImpl.java +++ b/siam-user/user-provider/src/main/java/com/siam/package_user/service_impl/MemberServiceImpl.java @@ -45,6 +45,7 @@ import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import java.io.IOException; @@ -84,6 +85,7 @@ public class MemberServiceImpl implements MemberService { @Autowired private SettingFeignApi settingFeignApi; + @Lazy @Autowired private MemberBillingRecordService memberBillingRecordService; @@ -93,6 +95,7 @@ public class MemberServiceImpl implements MemberService { @Autowired private CouponsFeignApi couponsFeignApi; + @Lazy @Autowired private MemberInviteRelationService memberInviteRelationService; diff --git a/siam-user/user-provider/src/main/resources/application-local.yml b/siam-user/user-provider/src/main/resources/application-local.yml index 3d9576a..a38c96a 100644 --- a/siam-user/user-provider/src/main/resources/application-local.yml +++ b/siam-user/user-provider/src/main/resources/application-local.yml @@ -5,9 +5,9 @@ server: spring: #mysql datasource: - url: jdbc:mysql://127.0.0.1:3306/siam_cloud?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8 + url: jdbc:mysql://127.0.0.1:3306/siam_cloud?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true username: root - password: root + password: 123456 #redis单例模式 redis: @@ -31,6 +31,18 @@ spring: application: name: user-siam + # Nacos注册中心/配置中心 + cloud: + nacos: + discovery: + server-addr: 127.0.0.1:8848 + config: + server-addr: 127.0.0.1:8848 + file-extension: yaml + config: + import: + - optional:nacos:${spring.application.name}-local.yaml + jackson: #时间戳统一转换为指定格式 date-format: yyyy/MM/dd HH:mm:ss @@ -90,17 +102,7 @@ mybatis-plus: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl -#eureka配置 -eureka: - client: - service-url: - defaultZone: http://127.0.0.1:9000/eureka/ - register-with-eureka: true - fetch-registry: true - instance: - #配置使用ip地址来注册(默认是主机名称) - prefer-ip-address: true - #心跳检测暂时不配置 +# Nacos注册中心/配置中心 #feign内部服务调用超时配置-第二种 feign: @@ -112,24 +114,31 @@ feign: # Seata Config seata: - application-id: user-service + application-id: ${spring.application.name} tx-service-group: my_test_tx_group service: vgroup-mapping: - # 此处配置对应Server端配置registry.eureka.application的值 my_test_tx_group: default registry: - type: eureka - eureka: - service-url: http://127.0.0.1:9000/eureka/ - weight: 1 + type: nacos + nacos: + application: seata-server + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public + config: + type: nacos + nacos: + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public #springboot admin相关配置 management: endpoints: web: exposure: - include: "*" #'prometheus,health' + include: "health,prometheus,info" exclude: "shutdown" base-path: /actuator endpoint: @@ -154,6 +163,8 @@ management: enabled: false elasticsearch: enabled: false + mail: + enabled: false #日志配置 logging: diff --git a/siam-util/pom.xml b/siam-util/pom.xml index e329fc5..e93bc2b 100644 --- a/siam-util/pom.xml +++ b/siam-util/pom.xml @@ -32,8 +32,6 @@ UTF-8 - 1.8 - 1.8 \ No newline at end of file diff --git a/siam-util/util-api/pom.xml b/siam-util/util-api/pom.xml index 4f822b6..58b3cf6 100644 --- a/siam-util/util-api/pom.xml +++ b/siam-util/util-api/pom.xml @@ -16,8 +16,6 @@ UTF-8 - 1.8 - 1.8 @@ -31,7 +29,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 exec diff --git a/siam-util/util-api/src/main/java/com/siam/package_util/entity/ScheduledTask.java b/siam-util/util-api/src/main/java/com/siam/package_util/entity/ScheduledTask.java index 5a85c5a..3cee68b 100644 --- a/siam-util/util-api/src/main/java/com/siam/package_util/entity/ScheduledTask.java +++ b/siam-util/util-api/src/main/java/com/siam/package_util/entity/ScheduledTask.java @@ -3,34 +3,33 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Date; @TableName("tb_scheduled_task") -@ApiModel(value = "定时任务表") + @Schema(description= "定时任务表") public class ScheduledTask { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "任务名称") + @Schema(description = "任务名称") private String name; - @ApiModelProperty(notes = "任务代码") + @Schema(description = "任务代码") private String code; - @ApiModelProperty(notes = "执行频率") + @Schema(description = "执行频率") private String frequency; - @ApiModelProperty(notes = "执行状态 1=未执行 2=正在执行") + @Schema(description = "执行状态 1=未执行 2=正在执行") private Integer state; - @ApiModelProperty(notes = "最后执行开始时间") + @Schema(description = "最后执行开始时间") private Date lastStartTime; - @ApiModelProperty(notes = "最后执行结束时间") + @Schema(description = "最后执行结束时间") private Date lastEndTime; public Integer getId() { diff --git a/siam-util/util-api/src/main/java/com/siam/package_util/entity/ScheduledTaskLog.java b/siam-util/util-api/src/main/java/com/siam/package_util/entity/ScheduledTaskLog.java index 06fabd6..e8219a4 100644 --- a/siam-util/util-api/src/main/java/com/siam/package_util/entity/ScheduledTaskLog.java +++ b/siam-util/util-api/src/main/java/com/siam/package_util/entity/ScheduledTaskLog.java @@ -3,34 +3,33 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Date; @TableName("tb_scheduled_task_log") -@ApiModel(value = "定时任务执行日志表") + @Schema(description= "定时任务执行日志表") public class ScheduledTaskLog { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "任务代码") + @Schema(description = "任务代码") private String scheduledTaskCode; - @ApiModelProperty(notes = "执行状态 1=执行成功 2=执行出错") + @Schema(description = "执行状态 1=执行成功 2=执行出错") private Integer state; - @ApiModelProperty(notes = "错误描述") + @Schema(description = "错误描述") private String error; - @ApiModelProperty(notes = "执行主机名称") + @Schema(description = "执行主机名称") private String hostName; - @ApiModelProperty(notes = "执行主机ip地址") + @Schema(description = "执行主机ip地址") private String hostIpAddress; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; public Integer getId() { diff --git a/siam-util/util-api/src/main/java/com/siam/package_util/entity/Setting.java b/siam-util/util-api/src/main/java/com/siam/package_util/entity/Setting.java index d81a4da..0b93d46 100644 --- a/siam-util/util-api/src/main/java/com/siam/package_util/entity/Setting.java +++ b/siam-util/util-api/src/main/java/com/siam/package_util/entity/Setting.java @@ -3,8 +3,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; diff --git a/siam-util/util-api/src/main/java/com/siam/package_util/entity/SmsLog.java b/siam-util/util-api/src/main/java/com/siam/package_util/entity/SmsLog.java index ecdda2b..0bffc29 100644 --- a/siam-util/util-api/src/main/java/com/siam/package_util/entity/SmsLog.java +++ b/siam-util/util-api/src/main/java/com/siam/package_util/entity/SmsLog.java @@ -3,42 +3,41 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.Date; @Data @TableName("tb_sms_log") -@ApiModel(value = "短信验证码记录表") + @Schema(description= "短信验证码记录表") public class SmsLog { @TableId(type = IdType.AUTO) private Integer id; - @ApiModelProperty(notes = "用户id") + @Schema(description = "用户id") private Integer memberId; - @ApiModelProperty(notes = "手机号") + @Schema(description = "手机号") private String mobile; - @ApiModelProperty(notes = "短信类型 注册=register;登录=login;验证手机号=verification;找回密码=findpwd") + @Schema(description = "短信类型 注册=register;登录=login;验证手机号=verification;找回密码=findpwd") private String type; - @ApiModelProperty(notes = "创建时间") + @Schema(description = "创建时间") private Date createTime; - @ApiModelProperty(notes = "请求ip") + @Schema(description = "请求ip") private String ip; - @ApiModelProperty(notes = "短信验证码") + @Schema(description = "短信验证码") private String verifyCode; - @ApiModelProperty(notes = "描述") + @Schema(description = "描述") private String description; - @ApiModelProperty(notes = "发送状态 1-发送成功,2-发送失败") + @Schema(description = "发送状态 1-发送成功,2-发送失败") private Boolean states; //页码 diff --git a/siam-util/util-api/src/main/java/com/siam/package_util/entity/SysMessage.java b/siam-util/util-api/src/main/java/com/siam/package_util/entity/SysMessage.java index 8ea2a2d..f379797 100644 --- a/siam-util/util-api/src/main/java/com/siam/package_util/entity/SysMessage.java +++ b/siam-util/util-api/src/main/java/com/siam/package_util/entity/SysMessage.java @@ -1,7 +1,6 @@ package com.siam.package_util.entity; import com.baomidou.mybatisplus.annotation.*; -import com.sun.org.apache.xpath.internal.operations.Bool; import lombok.Data; import java.io.Serializable; diff --git a/siam-util/util-api/src/main/java/com/siam/package_util/model/param/PictureUploadRecordParam.java b/siam-util/util-api/src/main/java/com/siam/package_util/model/param/PictureUploadRecordParam.java index c582420..a2e0134 100644 --- a/siam-util/util-api/src/main/java/com/siam/package_util/model/param/PictureUploadRecordParam.java +++ b/siam-util/util-api/src/main/java/com/siam/package_util/model/param/PictureUploadRecordParam.java @@ -3,7 +3,7 @@ import com.siam.package_util.entity.PictureUploadRecord; import lombok.Data; -import javax.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotBlank; @Data public class PictureUploadRecordParam extends PictureUploadRecord { diff --git a/siam-util/util-api/src/main/java/com/siam/package_util/model/param/SearchParam.java b/siam-util/util-api/src/main/java/com/siam/package_util/model/param/SearchParam.java index 8c848af..76ed814 100644 --- a/siam-util/util-api/src/main/java/com/siam/package_util/model/param/SearchParam.java +++ b/siam-util/util-api/src/main/java/com/siam/package_util/model/param/SearchParam.java @@ -2,7 +2,7 @@ import lombok.Data; -import javax.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotBlank; @Data public class SearchParam { diff --git a/siam-util/util-provider/pom.xml b/siam-util/util-provider/pom.xml index 425d00f..2bd2a4d 100644 --- a/siam-util/util-provider/pom.xml +++ b/siam-util/util-provider/pom.xml @@ -16,8 +16,6 @@ UTF-8 - 1.8 - 1.8 @@ -91,51 +89,40 @@ - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - 2.1.2.RELEASE - - - + com.alibaba.cloud - spring-cloud-starter-alibaba-seata - 2021.1 - - - io.seata - seata-spring-boot-starter - - + spring-cloud-starter-alibaba-nacos-discovery + - io.seata - seata-spring-boot-starter - 1.3.0 + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config org.springframework.boot spring-boot-starter-actuator - 2.3.3.RELEASE io.micrometer micrometer-registry-prometheus - 1.5.4 net.logstash.logback logstash-logback-encoder - 6.6 + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui @@ -145,7 +132,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.7.2 com.siam.package_util.UtilApplication diff --git a/siam-util/util-provider/src/main/java/com/siam/package_util/UtilApplication.java b/siam-util/util-provider/src/main/java/com/siam/package_util/UtilApplication.java index 9aea891..613ca2a 100644 --- a/siam-util/util-provider/src/main/java/com/siam/package_util/UtilApplication.java +++ b/siam-util/util-provider/src/main/java/com/siam/package_util/UtilApplication.java @@ -3,14 +3,19 @@ import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.scheduling.annotation.EnableScheduling; @EnableScheduling @EnableFeignClients("com.siam") -@EnableEurekaClient -@SpringBootApplication(scanBasePackages = "com.siam") +@EnableDiscoveryClient +@SpringBootApplication(scanBasePackages = "com.siam", exclude = { + MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class +}) @MapperScan(basePackages = {"com.siam.**.mapper"}) public class UtilApplication { diff --git a/siam-util/util-provider/src/main/java/com/siam/package_util/config/MybatisPlusConfig.java b/siam-util/util-provider/src/main/java/com/siam/package_util/config/MybatisPlusConfig.java index 7c07616..dfabb28 100644 --- a/siam-util/util-provider/src/main/java/com/siam/package_util/config/MybatisPlusConfig.java +++ b/siam-util/util-provider/src/main/java/com/siam/package_util/config/MybatisPlusConfig.java @@ -1,6 +1,8 @@ package com.siam.package_util.config; -import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -19,8 +21,11 @@ public class MybatisPlusConfig { * 分页插件 */ @Bean - public PaginationInterceptor paginationInterceptor() { - return new PaginationInterceptor(); + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); + interceptor.addInnerInterceptor(paginationInnerInterceptor); + return interceptor; } } \ No newline at end of file diff --git a/siam-util/util-provider/src/main/java/com/siam/package_util/config/Swagger2Config.java b/siam-util/util-provider/src/main/java/com/siam/package_util/config/Swagger2Config.java deleted file mode 100644 index 1267a31..0000000 --- a/siam-util/util-provider/src/main/java/com/siam/package_util/config/Swagger2Config.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.siam.package_util.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; - -@Configuration -@EnableSwagger2 -public class Swagger2Config { - - @Bean - public Docket createRestApi() { - return new Docket(DocumentationType.SWAGGER_2) - .apiInfo(apiInfo()) - .select() - .apis(RequestHandlerSelectors.basePackage("com.siam"))//扫描包路径 - .paths(PathSelectors.any()) - .build(); - } - - // 构建api文档的详细信息函数,注意这里的注解引用的是哪个 - private ApiInfo apiInfo() { - return new ApiInfoBuilder() - .title("暹罗外卖-工具服务接口文档")//页面标题 - .description("")//描述 - .version("1.0")//版本号 - .build(); - } -} \ No newline at end of file diff --git a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/admin/AdminPictureUploadRecordController.java b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/admin/AdminPictureUploadRecordController.java index 5b30895..73b99f9 100644 --- a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/admin/AdminPictureUploadRecordController.java +++ b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/admin/AdminPictureUploadRecordController.java @@ -5,8 +5,11 @@ import com.siam.package_common.entity.BasicData; import com.siam.package_common.entity.BasicResult; import com.siam.package_util.entity.PictureUploadRecord; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -15,13 +18,13 @@ @RestController @RequestMapping(value = "/rest/admin/pictureUploadRecord") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台图片上传记录模块相关接口", description = "AdminPictureUploadRecordController") +@Tag(name = "后台图片上传记录模块相关接口", description = "AdminPictureUploadRecordController") public class AdminPictureUploadRecordController { @Autowired private PictureUploadRecordService pictureUploadRecordService; - @ApiOperation(value = "图片上传记录列表") + @Operation(summary = "图片上传记录列表") @PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) PictureUploadRecord pictureUploadRecord){ BasicData basicResult = new BasicData(); @@ -30,15 +33,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) PictureUploadRecord return BasicResult.success(page); } - /*@ApiOperation(value = "图片上传记录创建") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "图片上传记录主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "图片上传记录名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "detail", value = "图片上传记录详情描述", required = false, paramType = "query", dataType = "string") - }) - @PostMapping(value = "/insert") + /*@Operation(summary = "图片上传记录创建")@PostMapping(value = "/insert") public BasicResult insert(PictureUploadRecord pictureUploadRecord){ BasicResult basicResult = new BasicResult(); @@ -53,15 +48,7 @@ public BasicResult insert(PictureUploadRecord pictureUploadRecord){ } - @ApiOperation(value = "图片上传记录修改") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "图片上传记录主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "图片上传记录名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "detail", value = "图片上传记录详情描述", required = false, paramType = "query", dataType = "string") - }) - @PutMapping(value = "/update") + @Operation(summary = "图片上传记录修改")@PutMapping(value = "/update") public BasicResult update(PictureUploadRecord pictureUploadRecord){ BasicResult basicResult = new BasicResult(); @@ -75,11 +62,8 @@ public BasicResult update(PictureUploadRecord pictureUploadRecord){ }*/ -// @ApiOperation(value = "图片上传记录删除") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "id", value = "图片上传记录主键id集合(批量删除时id以逗号分隔)", required = true, paramType = "query", dataType = "String") -// }) -// @DeleteMapping(value = "/delete") +// @Operation(summary = "图片上传记录删除") +//// @DeleteMapping(value = "/delete") // public BasicResult delete(@RequestBody @Validated(value = {}) AdminParam param @RequestParam(value = "ids") List ids){ // BasicResult basicResult = new BasicResult(); // for (Integer id : ids) { diff --git a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/admin/AdminSettingController.java b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/admin/AdminSettingController.java index c7b4aee..3f19ecb 100644 --- a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/admin/AdminSettingController.java +++ b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/admin/AdminSettingController.java @@ -7,8 +7,9 @@ import com.siam.package_goods.feign.GoodsSpecificationOptionFeignApi; import com.siam.package_util.entity.Setting; import com.siam.package_util.service.SettingService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -19,7 +20,7 @@ @RestController @RequestMapping(value = "/rest/admin/setting") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台基础数据设置模块相关接口", description = "AdminSettingController") +@Tag(name = "后台基础数据设置模块相关接口", description = "AdminSettingController") public class AdminSettingController { @Autowired @@ -28,7 +29,7 @@ public class AdminSettingController { @Autowired private GoodsSpecificationOptionFeignApi goodsSpecificationOptionFeignApi; - /*@ApiOperation(value = "基础数据设置列表") + /*@Operation(summary = "基础数据设置列表") @PostMapping(value = "/list") public BasicResult list(int pageNo, int pageSize, Setting setting){ BasicData basicResult = new BasicData(); @@ -37,7 +38,7 @@ public BasicResult list(int pageNo, int pageSize, Setting setting){ return BasicResult.success(page); }*/ - @ApiOperation(value = "基础数据设置列表") + @Operation(summary = "基础数据设置列表") @PostMapping(value = "/selectCurrent") public BasicResult selectCurrent(@RequestBody @Validated(value = {}) Setting setting){ BasicData basicResult = new BasicData(); @@ -52,7 +53,7 @@ public BasicResult selectCurrent(@RequestBody @Validated(value = {}) Setting set } @AdminPermission - @ApiOperation(value = "修改基础数据设置") + @Operation(summary = "修改基础数据设置") @PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) Setting setting){ BasicResult basicResult = new BasicResult(); diff --git a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/admin/AdminUploadController.java b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/admin/AdminUploadController.java index 105f85e..8e05791 100644 --- a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/admin/AdminUploadController.java +++ b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/admin/AdminUploadController.java @@ -3,7 +3,8 @@ import com.siam.package_common.entity.BasicResult; import com.siam.package_common.exception.StoneCustomerException; import com.siam.package_common.util.OSSUtils; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.PostMapping; @@ -17,7 +18,7 @@ @RestController @RequestMapping(value = "/rest/admin") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台上传图片模块相关接口", description = "AdminUploadController") +@Tag(name = "后台上传图片模块相关接口", description = "AdminUploadController") public class AdminUploadController { @Autowired diff --git a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/member/SettingController.java b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/member/SettingController.java index f5e1e0b..9491ee1 100644 --- a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/member/SettingController.java +++ b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/member/SettingController.java @@ -5,10 +5,16 @@ import com.siam.package_common.entity.BasicResult; import com.siam.package_util.entity.Setting; import com.siam.package_util.service.SettingService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -22,20 +28,12 @@ @RestController @RequestMapping(value = "/rest/setting") @Transactional(rollbackFor = Exception.class) -@Api(tags = "基础数据设置模块相关接口", description = "SettingController") +@Tag(name = "基础数据设置模块相关接口", description = "SettingController") public class SettingController { @Autowired private SettingService settingService; - @ApiOperation(value = "查询基础数据设置") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "基础数据设置表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "purchaseRewardPoints", value = "购买一杯奶茶赠送积分数量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "registrationRewardPoints", value = "新用户注册奖励积分数量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20"), - }) - @PostMapping(value = "/selectCurrent") + @Operation(summary = "查询基础数据设置")@PostMapping(value = "/selectCurrent") public BasicResult selectCurrent(@RequestBody @Validated(value = {}) Setting setting){ BasicData basicResult = new BasicData(); diff --git a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/member/SmsLogController.java b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/member/SmsLogController.java index aa88992..15ce823 100644 --- a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/member/SmsLogController.java +++ b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/member/SmsLogController.java @@ -9,10 +9,16 @@ import com.siam.package_common.util.RedisUtils; import com.siam.package_util.entity.SmsLog; import com.siam.package_util.service.SmsLogService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -26,7 +32,7 @@ @RestController @RequestMapping(value = "/rest/smsLog") @Transactional(rollbackFor = Exception.class) -@Api(tags = "短信验证码记录模块相关接口", description = "SmsLogController") +@Tag(name = "短信验证码记录模块相关接口", description = "SmsLogController") public class SmsLogController { @Autowired @@ -39,12 +45,7 @@ public class SmsLogController { private RedisUtils redisUtils; @PostMapping(value = "/sendMobileCode") - @ApiOperation(value = "发送手机验证码") - @ApiImplicitParams({ - @ApiImplicitParam(name = "mobile", value = "手机号", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "type", value = "短信类型 注册=register;登录=login;验证手机号=verification;找回密码=findpwd", required = true, paramType = "query", dataType = "string") - }) - public BasicResult sendMobileCode(@RequestBody @Validated(value = {}) SmsLog smsLog){ + @Operation(summary = "发送手机验证码")public BasicResult sendMobileCode(@RequestBody @Validated(value = {}) SmsLog smsLog){ BasicResult basicResult = new BasicResult(); if(!CommonUtils.isMobile(smsLog.getMobile())){ basicResult.setSuccess(false); diff --git a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/member/SystemUsageRecordController.java b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/member/SystemUsageRecordController.java index 8744abc..b736111 100644 --- a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/member/SystemUsageRecordController.java +++ b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/member/SystemUsageRecordController.java @@ -8,8 +8,9 @@ import com.siam.package_user.entity.Member; import com.siam.package_user.entity.MemberToken; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -19,13 +20,13 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.Date; @RestController @RequestMapping(value = "/rest/systemUsageRecord") @Transactional(rollbackFor = Exception.class) -@Api(tags = "后台系统使用记录模块相关接口", description = "SystemUsageRecordController") +@Tag(name = "后台系统使用记录模块相关接口", description = "SystemUsageRecordController") public class SystemUsageRecordController { @Autowired @@ -34,7 +35,7 @@ public class SystemUsageRecordController { @Autowired private MemberSessionManager memberSessionManager; - @ApiOperation(value = "新增系统使用记录") + @Operation(summary = "新增系统使用记录") @PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) SystemUsageRecord systemUsageRecord, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); diff --git a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/member/UploadController.java b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/member/UploadController.java index ba47cf2..6aa7d82 100644 --- a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/member/UploadController.java +++ b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/member/UploadController.java @@ -6,8 +6,9 @@ import com.siam.package_user.auth.cache.MemberSessionManager; import com.siam.package_user.entity.Member; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.PostMapping; @@ -21,7 +22,7 @@ @RestController @RequestMapping(value = "/rest/member") @Transactional(rollbackFor = Exception.class) -@Api(tags = "用户上传图片模块相关接口", description = "AdminUploadController") +@Tag(name = "用户上传图片模块相关接口", description = "AdminUploadController") public class UploadController { @Autowired @@ -30,7 +31,7 @@ public class UploadController { @Autowired private MemberSessionManager memberSessionManager; - @ApiOperation(value = "用户上传单张图片") + @Operation(summary = "用户上传单张图片") @PostMapping(value = "/uploadSingleImage") public BasicResult uploadSingleImage(@RequestParam("file") MultipartFile file) { Member loginMember = memberSessionManager.getSession(TokenUtil.getToken()); @@ -43,7 +44,7 @@ public BasicResult uploadSingleImage(@RequestParam("file") MultipartFile file) { return BasicResult.success(imageUrl); } - @ApiOperation(value = "用户上传多张图片") + @Operation(summary = "用户上传多张图片") @PostMapping(value = "/uploadMultipleImage") public BasicResult uploadMultipleImage(@RequestParam("fileList") List fileList) { Member loginMember = memberSessionManager.getSession(TokenUtil.getToken()); diff --git a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/merchant/MerchantPictureUploadRecordController.java b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/merchant/MerchantPictureUploadRecordController.java index 7deac53..4d6c0dd 100644 --- a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/merchant/MerchantPictureUploadRecordController.java +++ b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/merchant/MerchantPictureUploadRecordController.java @@ -8,10 +8,16 @@ import com.siam.package_user.util.TokenUtil; import com.siam.package_util.entity.PictureUploadRecord; import com.siam.package_util.service.PictureUploadRecordService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -20,12 +26,12 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; @RestController @RequestMapping(value = "/rest/merchant/pictureUploadRecord") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端图片上传记录模块相关接口【暂无调用】", description = "MerchantPictureUploadRecordController") +@Tag(name = "商家端图片上传记录模块相关接口【暂无调用】", description = "MerchantPictureUploadRecordController") public class MerchantPictureUploadRecordController { @Autowired @@ -34,17 +40,7 @@ public class MerchantPictureUploadRecordController { @Autowired private MerchantSessionManager merchantSessionManager; - @ApiOperation(value = "图片上传记录列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "商品名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "detail", value = "图片上传记录详情描述", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - }) - @PostMapping(value = "/list") + @Operation(summary = "图片上传记录列表")@PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) PictureUploadRecord pictureUploadRecord, HttpServletRequest request){ BasicData basicResult = new BasicData(); diff --git a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/merchant/MerchantSettingController.java b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/merchant/MerchantSettingController.java index c1d9703..df914aa 100644 --- a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/merchant/MerchantSettingController.java +++ b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/merchant/MerchantSettingController.java @@ -4,7 +4,7 @@ @RestController @RequestMapping(value = "/rest/merchant/setting") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端基础数据设置模块相关接口", description = "MerchantSettingController") +@Tag(name = "商家端基础数据设置模块相关接口", description = "MerchantSettingController") public class MerchantSettingController { @Autowired @@ -13,15 +13,7 @@ public class MerchantSettingController { @Autowired private GoodsSpecificationOptionFeignApi goodsSpecificationOptionService; - @ApiOperation(value = "基础数据设置列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "基础数据设置表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "purchaseRewardPoints", value = "购买一杯奶茶赠送积分数量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "registrationRewardPoints", value = "新用户注册奖励积分数量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - }) - @PostMapping(value = "/list") + @Operation(summary = "基础数据设置列表")@PostMapping(value = "/list") public BasicResult list(int pageNo, int pageSize, Setting setting){ BasicData basicResult = new BasicData(); Page page = settingService.getListByPage(param.getPageNo(), param.getPageSize(), setting); @@ -29,13 +21,7 @@ public BasicResult list(int pageNo, int pageSize, Setting setting){ return BasicResult.success(page); } - @ApiOperation(value = "修改基础数据设置") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "基础数据设置主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "purchaseRewardPoints", value = "购买一杯奶茶赠送积分数量", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "registrationRewardPoints", value = "新用户注册奖励积分数量", required = false, paramType = "query", dataType = "int"), - }) - @PutMapping(value = "/update") + @Operation(summary = "修改基础数据设置")@PutMapping(value = "/update") public BasicResult update(Setting setting){ BasicResult basicResult = new BasicResult(); diff --git a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/merchant/MerchantUploadController.java b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/merchant/MerchantUploadController.java index c8813ad..ddd2c03 100644 --- a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/merchant/MerchantUploadController.java +++ b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/merchant/MerchantUploadController.java @@ -6,8 +6,9 @@ import com.siam.package_merchant.auth.cache.MerchantSessionManager; import com.siam.package_merchant.entity.Merchant; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.PostMapping; @@ -21,7 +22,7 @@ @RestController @RequestMapping(value = "/rest/merchant") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端上传图片模块相关接口", description = "MerchantUploadController") +@Tag(name = "商家端上传图片模块相关接口", description = "MerchantUploadController") public class MerchantUploadController { @Autowired @@ -30,7 +31,7 @@ public class MerchantUploadController { @Autowired private MerchantSessionManager merchantSessionManager; - @ApiOperation(value = "用户上传单张图片") + @Operation(summary = "用户上传单张图片") @PostMapping(value = "/uploadSingleImage") public BasicResult uploadSingleImage(@RequestParam("file") MultipartFile file) { Merchant loginMerchant = merchantSessionManager.getSession(TokenUtil.getToken()); @@ -43,7 +44,7 @@ public BasicResult uploadSingleImage(@RequestParam("file") MultipartFile file) { return BasicResult.success(imageUrl); } - @ApiOperation(value = "用户上传多张图片") + @Operation(summary = "用户上传多张图片") @PostMapping(value = "/uploadMultipleImage") public BasicResult uploadMultipleImage(@RequestParam("fileList") List fileList) { Merchant loginMerchant = merchantSessionManager.getSession(TokenUtil.getToken()); diff --git a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/merchant/internal/MerchantPrinterController.java b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/merchant/internal/MerchantPrinterController.java index 0343fe4..1ae4374 100644 --- a/siam-util/util-provider/src/main/java/com/siam/package_util/controller/merchant/internal/MerchantPrinterController.java +++ b/siam-util/util-provider/src/main/java/com/siam/package_util/controller/merchant/internal/MerchantPrinterController.java @@ -11,22 +11,28 @@ import com.siam.package_util.entity.internal.Printer; import com.siam.package_merchant.entity.Merchant; import com.siam.package_user.util.TokenUtil; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.Date; @RestController @RequestMapping(value = "/rest/merchant/printer") @Transactional(rollbackFor = Exception.class) -@Api(tags = "商家端商家打印机信息模块相关接口", description = "MerchantPrinterController") +@Tag(name = "商家端商家打印机信息模块相关接口", description = "MerchantPrinterController") public class MerchantPrinterController { @Autowired @@ -38,17 +44,7 @@ public class MerchantPrinterController { // @Autowired // private MerchantService merchantService; - @ApiOperation(value = "打印机信息列表") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "商品表主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "商品名称", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "detail", value = "商家打印机信息详情描述", required = false, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "pageNo", value = "页码(值为-1不分页)", required = true, paramType = "query", dataType = "int", defaultValue = "1"), - @ApiImplicitParam(name = "pageSize", value = "页数", required = true, paramType = "query", dataType = "int", defaultValue = "20") - }) - @PostMapping(value = "/list") + @Operation(summary = "打印机信息列表")@PostMapping(value = "/list") public BasicResult list(@RequestBody @Validated(value = {}) Printer printer, HttpServletRequest request){ BasicData basicResult = new BasicData(); @@ -61,15 +57,7 @@ public BasicResult list(@RequestBody @Validated(value = {}) Printer printer, Htt return BasicResult.success(page); } - @ApiOperation(value = "打印机信息创建") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "打印机信息主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "打印机信息名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "detail", value = "商家打印机信息详情描述", required = false, paramType = "query", dataType = "string") - }) - @PostMapping(value = "/insert") + @Operation(summary = "打印机信息创建")@PostMapping(value = "/insert") public BasicResult insert(@RequestBody @Validated(value = {}) Printer printer, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); @@ -88,15 +76,7 @@ public BasicResult insert(@RequestBody @Validated(value = {}) Printer printer, H } @MerchantPermission - @ApiOperation(value = "打印机信息修改") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "打印机信息主键id", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "name", value = "打印机信息名称", required = true, paramType = "query", dataType = "string"), - @ApiImplicitParam(name = "sortNumber", value = "排序", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "isDisabled", value = "是否启用 0-启用、1-禁用", required = false, paramType = "query", dataType = "int"), - @ApiImplicitParam(name = "detail", value = "商家打印机信息详情描述", required = false, paramType = "query", dataType = "string") - }) - @PutMapping(value = "/update") + @Operation(summary = "打印机信息修改")@PutMapping(value = "/update") public BasicResult update(@RequestBody @Validated(value = {}) Printer printer, HttpServletRequest request){ BasicResult basicResult = new BasicResult(); @@ -121,11 +101,7 @@ public BasicResult update(@RequestBody @Validated(value = {}) Printer printer, H @MerchantPermission - @ApiOperation(value = "打印机信息删除") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "打印机信息主键id集合(批量删除时id以逗号分隔)", required = true, paramType = "query", dataType = "String") - }) - @DeleteMapping(value = "/delete") + @Operation(summary = "打印机信息删除")@DeleteMapping(value = "/delete") public BasicResult delete(@RequestBody @Validated(value = {}) Printer param){ BasicResult basicResult = new BasicResult(); //获取当前登录用户绑定的门店编号 diff --git a/siam-util/util-provider/src/main/java/com/siam/package_util/service_impl/PreviousWxNotifyServiceImpl.java b/siam-util/util-provider/src/main/java/com/siam/package_util/service_impl/PreviousWxNotifyServiceImpl.java index e2631ab..9a036a3 100644 --- a/siam-util/util-provider/src/main/java/com/siam/package_util/service_impl/PreviousWxNotifyServiceImpl.java +++ b/siam-util/util-provider/src/main/java/com/siam/package_util/service_impl/PreviousWxNotifyServiceImpl.java @@ -10,9 +10,18 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; +@Configuration +class RestTemplateConfig { + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } +} + @Slf4j @Service public class PreviousWxNotifyServiceImpl { @@ -23,11 +32,6 @@ public class PreviousWxNotifyServiceImpl { @Autowired private WxNotifyConfig wxNotifyConfig; - @Bean - public RestTemplate restTemplate() { - return new RestTemplate(); - } - @Autowired private RestTemplate restTemplate; @@ -70,12 +74,8 @@ public String pushOneUser(String openid) { * appid和appsecret到小程序后台获取,当然也可以让小程序开发人员给你传过来 * */ public String getAccess_token() { - //获取access_token String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" + "&appid=" + wxNotifyConfig.getAppId() + "&secret=" + wxNotifyConfig.getSecret(); - if(restTemplate==null){ - restTemplate = new RestTemplate(); - } String json = restTemplate.getForObject(url, String.class); JSONObject myJson = JSONObject.parseObject(json); return myJson.get("access_token").toString(); diff --git a/siam-util/util-provider/src/main/resources/application-local.yml b/siam-util/util-provider/src/main/resources/application-local.yml index 6bdbe46..a680e96 100644 --- a/siam-util/util-provider/src/main/resources/application-local.yml +++ b/siam-util/util-provider/src/main/resources/application-local.yml @@ -5,9 +5,9 @@ server: spring: #mysql datasource: - url: jdbc:mysql://127.0.0.1:3306/siam_cloud?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8 + url: jdbc:mysql://127.0.0.1:3306/siam_cloud?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true username: root - password: root + password: 123456 # #mongodb(默认时没有账号密码的) # # application: @@ -75,6 +75,18 @@ spring: application: name: util-siam + # Nacos注册中心/配置中心 + cloud: + nacos: + discovery: + server-addr: 127.0.0.1:8848 + config: + server-addr: 127.0.0.1:8848 + file-extension: yaml + config: + import: + - optional:nacos:${spring.application.name}-local.yaml + #配置文件上传大小限制 servlet: multipart: @@ -142,17 +154,7 @@ mybatis-plus: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl -#eureka配置 -eureka: - client: - service-url: - defaultZone: http://127.0.0.1:9000/eureka/ - register-with-eureka: true - fetch-registry: true - instance: - #配置使用ip地址来注册(默认是主机名称) - prefer-ip-address: true - #心跳检测暂时不配置 +# Nacos注册中心/配置中心 #feign内部服务调用超时配置 feign: @@ -173,24 +175,31 @@ rocketmq: # Seata Config seata: - application-id: util-service + application-id: ${spring.application.name} tx-service-group: my_test_tx_group service: vgroup-mapping: - # 此处配置对应Server端配置registry.eureka.application的值 my_test_tx_group: default registry: - type: eureka - eureka: - service-url: http://127.0.0.1:9000/eureka/ - weight: 1 + type: nacos + nacos: + application: seata-server + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public + config: + type: nacos + nacos: + server-addr: 127.0.0.1:8848 + group: SEATA_GROUP + namespace: public #springboot admin相关配置 management: endpoints: web: exposure: - include: "*" #'prometheus,health' + include: "health,prometheus,info" exclude: "shutdown" base-path: /actuator endpoint: @@ -215,6 +224,8 @@ management: enabled: false elasticsearch: enabled: false + mail: + enabled: false #芯烨云打印机开放 API相关配置 xinyeyun: diff --git a/siam-weixin/pom.xml b/siam-weixin/pom.xml index f3c97f5..e3c403d 100644 --- a/siam-weixin/pom.xml +++ b/siam-weixin/pom.xml @@ -22,8 +22,6 @@ UTF-8 - 1.8 - 1.8 diff --git a/siam-weixin/weixin-basic/pom.xml b/siam-weixin/weixin-basic/pom.xml index 4c3d6e4..803acef 100644 --- a/siam-weixin/weixin-basic/pom.xml +++ b/siam-weixin/weixin-basic/pom.xml @@ -16,8 +16,6 @@ UTF-8 - 1.8 - 1.8 diff --git a/siam-weixin/weixin-basic/src/main/java/com/siam/package_weixin_basic/util/IpUtils.java b/siam-weixin/weixin-basic/src/main/java/com/siam/package_weixin_basic/util/IpUtils.java index 558789c..2c66af2 100644 --- a/siam-weixin/weixin-basic/src/main/java/com/siam/package_weixin_basic/util/IpUtils.java +++ b/siam-weixin/weixin-basic/src/main/java/com/siam/package_weixin_basic/util/IpUtils.java @@ -2,7 +2,7 @@ import org.apache.commons.lang3.StringUtils; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; public class IpUtils { /** diff --git a/siam-weixin/weixin-pay/pom.xml b/siam-weixin/weixin-pay/pom.xml index bd4cf8b..dfed5ef 100644 --- a/siam-weixin/weixin-pay/pom.xml +++ b/siam-weixin/weixin-pay/pom.xml @@ -16,8 +16,6 @@ UTF-8 - 1.8 - 1.8 diff --git a/siam-weixin/weixin-pay/src/main/java/com/siam/package_weixin_pay/config/WxpayConfigDemo.java b/siam-weixin/weixin-pay/src/main/java/com/siam/package_weixin_pay/config/WxpayConfigDemo.java index 897cc02..5ddbe24 100644 --- a/siam-weixin/weixin-pay/src/main/java/com/siam/package_weixin_pay/config/WxpayConfigDemo.java +++ b/siam-weixin/weixin-pay/src/main/java/com/siam/package_weixin_pay/config/WxpayConfigDemo.java @@ -6,7 +6,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import javax.net.ssl.SSLContext; import java.io.*; diff --git a/siam-weixin/weixin-pay/src/main/java/com/siam/package_weixin_pay/entity/WxPayDto.java b/siam-weixin/weixin-pay/src/main/java/com/siam/package_weixin_pay/entity/WxPayDto.java index 5e1d543..cb813e2 100644 --- a/siam-weixin/weixin-pay/src/main/java/com/siam/package_weixin_pay/entity/WxPayDto.java +++ b/siam-weixin/weixin-pay/src/main/java/com/siam/package_weixin_pay/entity/WxPayDto.java @@ -3,8 +3,8 @@ import lombok.Data; import org.hibernate.validator.constraints.Range; -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; import java.math.BigDecimal; /** diff --git a/siam-weixin/weixin-pay/src/main/java/com/siam/package_weixin_pay/entity/WxpayConfig.java b/siam-weixin/weixin-pay/src/main/java/com/siam/package_weixin_pay/entity/WxpayConfig.java index 8f07eaf..8efb625 100644 --- a/siam-weixin/weixin-pay/src/main/java/com/siam/package_weixin_pay/entity/WxpayConfig.java +++ b/siam-weixin/weixin-pay/src/main/java/com/siam/package_weixin_pay/entity/WxpayConfig.java @@ -6,7 +6,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import javax.net.ssl.SSLContext; import java.io.FileNotFoundException; diff --git a/siam-weixin/weixin-pay/src/main/java/com/siam/package_weixin_pay/util/PayUtil.java b/siam-weixin/weixin-pay/src/main/java/com/siam/package_weixin_pay/util/PayUtil.java index aa74340..84505df 100644 --- a/siam-weixin/weixin-pay/src/main/java/com/siam/package_weixin_pay/util/PayUtil.java +++ b/siam-weixin/weixin-pay/src/main/java/com/siam/package_weixin_pay/util/PayUtil.java @@ -35,7 +35,7 @@ public static String sign(String text, String key, String input_charset) { * @return 签名结果 */ public static boolean verify(String text, String sign, String key, String input_charset) { - text = text + key; + text = text + "&key=" + key; String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset)); if (mysign.equals(sign)) { return true; diff --git a/siam-zuul/Dockerfile b/siam-zuul/Dockerfile deleted file mode 100644 index b0590e6..0000000 --- a/siam-zuul/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM openjdk:8-jdk-slim -LABEL maintainer=暹罗 - -COPY target/*.jar /app.jar -# ADD jmx_prometheus_javaagent-0.15.0.jar /opt/jmx.jar -# ADD jmx_exporter.yml /opt/jmx.yml - -# 设置JVM运行参数监控端口可以自定义 -ENV JAVA_JMX_PROMETHEUS="-javaagent:/opt/jmx.jar=0.0.0.0:9041:/opt/jmx.yml" -ENV JAVA_SW_AGENT="-javaagent:/opt/apache-skywalking-apm-bin/agent/skywalking-agent.jar -Dskywalking.agent.service_name=siam-zuul -Dskywalking.collector.backend_service=127.0.0.1:11800" -ENV JAVA_PROFILES_ACTIVE="" -ENV JAVA_OPTS="" - -# 应用端口 -EXPOSE 9041 - -# ENTRYPOINT ["sh", "-c", "java $JAVA_JMX_PROMETHEUS $JAVA_SW_AGENT -jar /app.jar"] -# ENTRYPOINT ["sh", "-c", "java -Xms128m -Xmx256m $JAVA_SW_AGENT -jar /app.jar"] -ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS $JAVA_PROFILES_ACTIVE -jar /app.jar"] diff --git a/siam-zuul/jmx_exporter.yml b/siam-zuul/jmx_exporter.yml deleted file mode 100644 index 92cab49..0000000 --- a/siam-zuul/jmx_exporter.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -lowercaseOutputLabelNames: true -lowercaseOutputName: true -whitelistObjectNames: ["java.lang:type=OperatingSystem"] -rules: - - pattern: 'java.lang<>((?!process_cpu_time)\w+):' - name: os_$1 - type: GAUGE - attrNameSnakeCase: true - diff --git a/siam-zuul/jmx_prometheus_javaagent-0.15.0.jar b/siam-zuul/jmx_prometheus_javaagent-0.15.0.jar deleted file mode 100644 index d896a21709c445b8b096d25764ddb21121d3f809..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 418240 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 z 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

@|14|*d4uX15oLOXdAF0@S$R0lUR(K%q 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

jXl$SGJhc_F=Q&J+ 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 diff --git a/siam-zuul/pom.xml b/siam-zuul/pom.xml deleted file mode 100644 index 5b48ae7..0000000 --- a/siam-zuul/pom.xml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - siam-parent - com.siam - 1.1 - ../siam-parent/pom.xml - - 4.0.0 - - siam-zuul - - siam-zuul - https://www.siamit.cn - - - UTF-8 - 1.8 - 1.8 - - - - - - com.siam - siam-common - 1.1 - - - - - com.siam - user-api - 1.1 - - - - - com.siam - merchant-api - 1.1 - - - - - com.siam - rider-api - 1.1 - - - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - 2.1.2.RELEASE - - - - - org.springframework.cloud - spring-cloud-starter-netflix-zuul - 2.1.2.RELEASE - - - - - com.netflix.servo - servo-core - 0.12.7 - - - - - org.springframework.boot - spring-boot-starter-actuator - 2.3.3.RELEASE - - - - - io.micrometer - micrometer-registry-prometheus - 1.5.4 - - - - - net.logstash.logback - logstash-logback-encoder - 6.6 - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - 2.7.2 - - - com.siam.package_zuul.ZuulApplication - ZIP - - - - - repackage - - - - - - - \ No newline at end of file diff --git a/siam-zuul/src/main/java/com/siam/package_zuul/ZuulApplication.java b/siam-zuul/src/main/java/com/siam/package_zuul/ZuulApplication.java deleted file mode 100644 index 6a1528f..0000000 --- a/siam-zuul/src/main/java/com/siam/package_zuul/ZuulApplication.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.siam.package_zuul; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.cloud.netflix.zuul.EnableZuulProxy; -import org.springframework.cloud.openfeign.EnableFeignClients; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Component; -import org.springframework.web.cors.CorsConfiguration; -import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import org.springframework.web.filter.CorsFilter; -import springfox.documentation.swagger.web.SwaggerResource; -import springfox.documentation.swagger.web.SwaggerResourcesProvider; - -import java.util.ArrayList; -import java.util.List; - -@EnableFeignClients("com.siam") -@EnableZuulProxy -@SpringBootApplication(scanBasePackages = "com.siam", exclude = {DataSourceAutoConfiguration.class}) -public class ZuulApplication -{ - public static void main(String[] args) - { - SpringApplication.run(ZuulApplication.class, args); - } - - /** - * Swagger配置 - */ - @Component - @Primary - class DocumentationConfig implements SwaggerResourcesProvider { - @Override - public List get() { - List resources = new ArrayList(); - resources.add(swaggerResource("用户服务","/api-user/v2/api-docs","1.0")); - resources.add(swaggerResource("商品服务","/api-goods/v2/api-docs","1.0")); - resources.add(swaggerResource("订单服务","/api-order/v2/api-docs","1.0")); - return resources; - } - - private SwaggerResource swaggerResource(String name, String location, String version) { - SwaggerResource swaggerResource = new SwaggerResource(); - swaggerResource.setName(name); - swaggerResource.setLocation(location); - swaggerResource.setSwaggerVersion(version); - return swaggerResource; - } - } - - /** - * 改用过滤器CorsFilter 来配置跨域,由于Filter的位置是在Interceptor之前的,问题得到解决 - */ - @Bean - public CorsFilter corsFilter() { - CorsConfiguration config = new CorsConfiguration(); - // 设置允许跨域请求的域名 - config.addAllowedOrigin("*"); - // 是否允许证书(这个不开启,请求会报错的) - config.setAllowCredentials(true); - // 设置允许的方法 - config.addAllowedMethod("*"); - // 允许任何头 - config.addAllowedHeader("*"); - config.addExposedHeader("token"); - UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource(); - configSource.registerCorsConfiguration("/**", config); - return new CorsFilter(configSource); - } -} \ No newline at end of file diff --git a/siam-zuul/src/main/java/com/siam/package_zuul/config/ActuatorConfig.java b/siam-zuul/src/main/java/com/siam/package_zuul/config/ActuatorConfig.java deleted file mode 100644 index f5bbebd..0000000 --- a/siam-zuul/src/main/java/com/siam/package_zuul/config/ActuatorConfig.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.siam.package_zuul.config; - -import io.micrometer.core.instrument.MeterRegistry; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class ActuatorConfig { - - @Bean - public MeterRegistryCustomizer configurer(@Value("${spring.application.name}") String applicationName) { - return (registry) -> registry.config().commonTags("application", applicationName); - } -} diff --git a/siam-zuul/src/main/java/com/siam/package_zuul/config/Swagger2Config.java b/siam-zuul/src/main/java/com/siam/package_zuul/config/Swagger2Config.java deleted file mode 100644 index dc9b4c0..0000000 --- a/siam-zuul/src/main/java/com/siam/package_zuul/config/Swagger2Config.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.siam.package_zuul.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; - -@Configuration -@EnableSwagger2 -public class Swagger2Config { - - @Bean - public Docket createRestApi() { - return new Docket(DocumentationType.SWAGGER_2) - .apiInfo(apiInfo()) - .select() - .apis(RequestHandlerSelectors.basePackage("com.siam"))//扫描包路径 - .paths(PathSelectors.any()) - .build(); - } - - // 构建api文档的详细信息函数,注意这里的注解引用的是哪个 - private ApiInfo apiInfo() { - return new ApiInfoBuilder() - .title("暹罗外卖-网关服务接口文档")//页面标题 - .description("")//描述 - .version("1.0")//版本号 - .build(); - } -} \ No newline at end of file diff --git a/siam-zuul/src/main/java/com/siam/package_zuul/config/WebMvcConfig.java b/siam-zuul/src/main/java/com/siam/package_zuul/config/WebMvcConfig.java deleted file mode 100644 index 0f61285..0000000 --- a/siam-zuul/src/main/java/com/siam/package_zuul/config/WebMvcConfig.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.siam.package_zuul.config; - -import com.siam.package_common.filter.StoneFilterRegistration; -import com.siam.package_common.filter.StoneFilterRegistry; -import com.siam.package_common.filter.StoneMappedFilter; -import com.siam.package_zuul.filter.AdminFilter; -import com.siam.package_zuul.filter.EncryptFilter; -import com.siam.package_zuul.filter.MemberFilter; -import com.siam.package_zuul.filter.MerchantFilter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; -import org.springframework.util.AntPathMatcher; - -import javax.annotation.PostConstruct; - -@Configuration -public class WebMvcConfig { - - @Autowired - private MemberFilter memberFilter; - - @Autowired - private MerchantFilter merchantFilter; - - @Autowired - private AdminFilter adminFilter; - - @Autowired - private EncryptFilter encryptFilter; - - @Autowired - private StoneFilterRegistry registry; - - @PostConstruct - public void init(){ - addFilters(); - } - - /** - * 重写添加拦截器方法并添加配置拦截器 - **/ - public void addFilters() { - //用户拦截器 - registry.addFilter(memberFilter) -// .addPathPatterns("/api-member/rest/member/**") - .addPathPatterns("/*/rest/member/**") - .excludePathPatterns("/api-user/rest/member/login") - .excludePathPatterns("/api-user/rest/member/loginByMobile") -// .excludePathPatterns("/api-user/rest/member/logout") - .excludePathPatterns("/api-user/rest/member/register") - .excludePathPatterns("/api-user/rest/member/verification/login") - .excludePathPatterns("/api-user/rest/member/weChat/login") - .excludePathPatterns("/api-order/rest/member/wxPay/notify") - .excludePathPatterns("/api-order/rest/member/wxPay/refundSuccessNotify");; - - //商户拦截器 - registry.addFilter(merchantFilter) -// .addPathPatterns("/api-member/rest/member/**") - .addPathPatterns("/*/rest/merchant/**") - .excludePathPatterns("/api-merchant/rest/merchant/login") - .excludePathPatterns("/api-merchant/rest/merchant/loginByMobile") - .excludePathPatterns("/api-merchant/rest/merchant/logout") - .excludePathPatterns("/api-merchant/rest/merchant/register") - .excludePathPatterns("/api-merchant/rest/merchant/registerByMobile") - .excludePathPatterns("/api-merchant/rest/merchant/verification/login") - .excludePathPatterns("/api-merchant/rest/merchant/forgetPassword/step1"); - - //管理员拦截器 - registry.addFilter(adminFilter) -// .addPathPatterns("/api-admin/rest/admin/**") - .addPathPatterns("/*/rest/admin/**") - .excludePathPatterns("/api-user/rest/admin/login") - .excludePathPatterns("/api-user/rest/admin/login") - .excludePathPatterns("/api-user/rest/admin/loginByMobile") - .excludePathPatterns("/api-user/rest/admin/logout") - .excludePathPatterns("/api-user/rest/admin/register") - .excludePathPatterns("/api-user/rest/admin/verification/login") - .excludePathPatterns("/api-user/rest/admin/forgetPassword/step1"); - } - - public boolean matches(String lookupPath) { - StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); - /*System.out.println(stackTraceElements.length); - for (StackTraceElement stackTraceElement : stackTraceElements) { - System.out.println(stackTraceElement.getClassName()); - }*/ - StoneFilterRegistration registration = registry.getFilter(stackTraceElements[2].getClassName()); - if(registration == null){ - return false; - }else{ - StoneMappedFilter filter = (StoneMappedFilter) registration.getFilter(); - return filter.matches(lookupPath, new AntPathMatcher()); - } - } -} \ No newline at end of file diff --git a/siam-zuul/src/main/java/com/siam/package_zuul/filter/AdminFilter.java b/siam-zuul/src/main/java/com/siam/package_zuul/filter/AdminFilter.java deleted file mode 100644 index f913faa..0000000 --- a/siam-zuul/src/main/java/com/siam/package_zuul/filter/AdminFilter.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.siam.package_zuul.filter; - -import com.netflix.zuul.ZuulFilter; -import com.netflix.zuul.context.RequestContext; -import com.netflix.zuul.exception.ZuulException; -import com.siam.package_common.constant.BaseCode; -import com.siam.package_common.entity.BasicResult; -import com.siam.package_common.filter.StoneFilter; -import com.siam.package_common.util.JsonUtils; -import com.siam.package_user.feign.AdminFeignApi; -import com.siam.package_user.auth.cache.AdminSessionManager; -import com.siam.package_user.entity.Admin; -import com.siam.package_user.util.TokenUtil; -import com.siam.package_zuul.config.WebMvcConfig; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; -import org.springframework.stereotype.Component; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * 管理员过滤器 - * - * @author 暹罗 - */ -@Slf4j -@Component -public class AdminFilter extends ZuulFilter implements StoneFilter { - - @Autowired - private AdminSessionManager adminSessionManager; - - @Autowired - private AdminFeignApi adminFeignApi; - - @Autowired - private WebMvcConfig webMvcConfig; - - /** - * 过滤类型 - * pre:路由之前 - * routing:路由之时 - * post: 路由之后 - * error:发送错误调用 - * @return - */ - @Override - public String filterType() { - return FilterConstants.PRE_TYPE; - } - - /** - * 过滤器执行顺序,当一个请求在同一个阶段存在多个过滤器的时候,多个过滤器执行顺序 - * @return - */ - @Override - public int filterOrder() { - return 0; - } - - /** - * 判断过滤器是否生效 - * @return - */ - @Override - public boolean shouldFilter() { - //此处只需要把当前请求路径 扔到我公共方法中检测是否需要拦截即可 - //通过当前上下文 获取 Request、Response对象 - RequestContext currentContext = RequestContext.getCurrentContext(); - HttpServletRequest request = currentContext.getRequest(); - - /*System.out.println("\nuri = " + request.getRequestURI()); - System.out.println("\nurl = " + request.getRequestURL());*/ - - return webMvcConfig.matches(request.getRequestURI()); - } - - @Override - public Object run() throws ZuulException { - //通过当前上下文 获取 Request、Response对象 - RequestContext currentContext = RequestContext.getCurrentContext(); - HttpServletRequest request = currentContext.getRequest(); - HttpServletResponse response = currentContext.getResponse(); - - //从header或param里面获取token(暂时这样写,兼容之前前端的写法) - String token = TokenUtil.getToken(); - log.debug("\ntoken = " + token); -// //把请求头信息继续往下传 -// currentContext.addZuulRequestHeader(TokenUtil.TOKEN_HEADER_NAME, token); - - if(token == null){ - BasicResult basicResult = new BasicResult(); - basicResult.setSuccess(false); - basicResult.setCode(BaseCode.TOKEN_ERR); - basicResult.setMessage("您暂未登录,请登陆后访问"); - log.debug("\n" + JsonUtils.toJson(basicResult)); - - //token验证失败,不会继续执行后续代码,网关服务直接响应给客户端 - currentContext.setSendZuulResponse(false); - currentContext.setResponseBody(JsonUtils.toJson(basicResult)); - currentContext.setResponseStatusCode(200); - return null; - } - - //TODO - 目前如果此处调用出错,该方法是不会继续执行,但是目标接口依旧是返回了数据 - Admin loginAdmin = adminSessionManager.getSession(token); - if(loginAdmin != null){ - return null; - } - - BasicResult basicResult = new BasicResult(); - basicResult.setSuccess(false); - basicResult.setCode(BaseCode.TOKEN_ERR); - basicResult.setMessage("您暂未登录,请登陆后访问"); - log.debug("\n" + JsonUtils.toJson(basicResult)); - /*try { - response.getWriter().print(JsonUtils.toJson(basicResult)); - } catch (IOException e) { - e.printStackTrace(); - }*/ - - //token验证失败,不会继续执行后续代码,网关服务直接响应给客户端 - currentContext.setSendZuulResponse(false); - currentContext.setResponseBody(JsonUtils.toJson(basicResult)); - currentContext.setResponseStatusCode(200); - return null; - } -} \ No newline at end of file diff --git a/siam-zuul/src/main/java/com/siam/package_zuul/filter/BodyReaderHttpServletRequestWrapper.java b/siam-zuul/src/main/java/com/siam/package_zuul/filter/BodyReaderHttpServletRequestWrapper.java deleted file mode 100644 index bbd6ec6..0000000 --- a/siam-zuul/src/main/java/com/siam/package_zuul/filter/BodyReaderHttpServletRequestWrapper.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.siam.package_zuul.filter; - -import javax.servlet.ReadListener; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; -import java.io.*; - -/** - * 功能描述:
- * 〈BodyReaderHttpServletRequestWrapper〉 - * - * @Author:hanxinghua - * @Date: 2020/7/4 - */ -public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { - - private final String body; - - public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException { - super(request); - StringBuilder stringBuilder = new StringBuilder(); - BufferedReader bufferedReader = null; - try { - InputStream inputStream = request.getInputStream(); - if (inputStream != null) { - bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); - char[] charBuffer = new char[128]; - int bytesRead = -1; - while ((bytesRead = bufferedReader.read(charBuffer)) > 0) { - stringBuilder.append(charBuffer, 0, bytesRead); - } - } else { - stringBuilder.append(""); - } - } finally { - if (bufferedReader != null) { - bufferedReader.close(); - } - } - body = stringBuilder.toString(); - } - - @Override - public ServletInputStream getInputStream() throws IOException { - final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes()); - ServletInputStream servletInputStream = new ServletInputStream() { - @Override - public boolean isFinished() { - return false; - } - - @Override - public boolean isReady() { - return false; - } - - @Override - public void setReadListener(ReadListener readListener) { - - } - - @Override - public int read() throws IOException { - return byteArrayInputStream.read(); - } - }; - return servletInputStream; - } - - @Override - public BufferedReader getReader() throws IOException { - return new BufferedReader(new InputStreamReader(this.getInputStream())); - } - - public String getBody() { - return this.body; - } -} \ No newline at end of file diff --git a/siam-zuul/src/main/java/com/siam/package_zuul/filter/Constant.java b/siam-zuul/src/main/java/com/siam/package_zuul/filter/Constant.java deleted file mode 100644 index 127da3c..0000000 --- a/siam-zuul/src/main/java/com/siam/package_zuul/filter/Constant.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.siam.package_zuul.filter; - -public class Constant { - - public static final String OPTIONS = "OPTIONS"; - - public static final String APP_JSON = "application/json"; - - public static final String CONTENT_TYPE = "Content-Type"; - - public static final String AUTHORIZATION = "Authorization"; - -} diff --git a/siam-zuul/src/main/java/com/siam/package_zuul/filter/EncryptFilter.java b/siam-zuul/src/main/java/com/siam/package_zuul/filter/EncryptFilter.java deleted file mode 100644 index 91da552..0000000 --- a/siam-zuul/src/main/java/com/siam/package_zuul/filter/EncryptFilter.java +++ /dev/null @@ -1,162 +0,0 @@ -package com.siam.package_zuul.filter; - -import com.netflix.zuul.ZuulFilter; -import com.netflix.zuul.context.RequestContext; -import com.netflix.zuul.exception.ZuulException; -import com.siam.package_common.entity.BasicResult; -import com.siam.package_common.filter.StoneFilter; -import com.siam.package_common.util.BeanUtils; -import com.siam.package_common.util.JsonUtils; -import com.siam.package_common.util.RedisUtils; -import com.siam.package_zuul.config.WebMvcConfig; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; -import org.springframework.stereotype.Component; -import org.springframework.util.StreamUtils; - -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.io.InputStream; -import java.math.BigDecimal; -import java.nio.charset.Charset; -import java.util.List; -import java.util.Map; - -/** - * 用户过滤器 - * - * @author 暹罗 - */ -@Slf4j -@Component -public class EncryptFilter extends ZuulFilter implements StoneFilter { - - @Autowired - private WebMvcConfig webMvcConfig; - - @Autowired - private RedisUtils redisUtils; - - /** - * 过滤类型 - * pre:路由之前 - * routing:路由之时 - * post: 路由之后 - * error:发送错误调用 - * @return - */ - @Override - public String filterType() { - return FilterConstants.POST_TYPE; - } - - /** - * 过滤器执行顺序,当一个请求在同一个阶段存在多个过滤器的时候,多个过滤器执行顺序 - * @return - */ - @Override - public int filterOrder() { - return 0; - } - - /** - * 判断过滤器是否生效 - * @return - */ - @Override - public boolean shouldFilter() { - //此处只需要把当前请求路径 扔到我公共方法中检测是否需要拦截即可 - //通过当前上下文 获取 Request、Response对象 - RequestContext currentContext = RequestContext.getCurrentContext(); - HttpServletRequest request = currentContext.getRequest(); - - /*System.out.println("\nuri = " + request.getRequestURI()); - System.out.println("\nurl = " + request.getRequestURL());*/ - - return webMvcConfig.matches(request.getRequestURI()); - } - - @Override - public Object run() throws ZuulException { - //如果开启了数据加密功能,则对返回数据进行加密处理 - Boolean isEncrypt = (Boolean) JsonUtils.toObject(redisUtils.get("isEncrypt").toString(), Boolean.class); - if(isEncrypt!=null && isEncrypt){ - //通过当前上下文 获取 Request、Response对象 - RequestContext currentContext = RequestContext.getCurrentContext(); - InputStream inputStream = currentContext.getResponseDataStream(); - try { - //获取原数据 - String body = StreamUtils.copyToString(inputStream, Charset.forName("UTF-8")); - //加密返回结果 - String resultBody = this.encrypt(body); - currentContext.setResponseBody(resultBody); - } catch (IOException e) { - e.printStackTrace(); - } - } - return null; - } - - /** - * 加密返回结果 - * - * @param body - * @return - * @author 暹罗 - */ - private String encrypt(String body){ - //加密规则: - //1、根据字段名加密 - //2、浮点数全部加密 - //3、所有字段值全部加密 - BasicResult basicResult = (BasicResult) JsonUtils.toObject(body, BasicResult.class); - Map data = (Map) basicResult.getData(); - if(data.containsKey("records")){ - //列表数据 - List> records; - try{ - records = (List) data.get("records"); - for (Map map : records) { - //渲染Map数据 - renderMap(map); - } - }catch (Exception ex){ - records = BeanUtils.objectsToMaps((List) data.get("records")); - for (Map map : records) { - //渲染Map数据 - renderMap(map); - } - } - }else{ - //详情等数据 - //渲染Map数据 - renderMap(data); - } - - return JsonUtils.toJson(basicResult); - } - - /** - * 渲染Map数据 - * - * @param map - * @return - * @author 暹罗 - */ - private void renderMap(Map map){ - for (String key : map.keySet()) { - if(key.equals("id") || key.endsWith("Id") - || key.equals("type") || key.endsWith("Type") - || key.equals("status") || key.endsWith("Status") - || key.startsWith("is")){ - continue; - } - if(map.get(key) instanceof String){ - map.put(key, "****"); - }else if(map.get(key) instanceof Integer || map.get(key) instanceof Double || map.get(key) instanceof BigDecimal){ - map.put(key, 0); - } - } - } -} \ No newline at end of file diff --git a/siam-zuul/src/main/java/com/siam/package_zuul/filter/MemberFilter.java b/siam-zuul/src/main/java/com/siam/package_zuul/filter/MemberFilter.java deleted file mode 100644 index f003c39..0000000 --- a/siam-zuul/src/main/java/com/siam/package_zuul/filter/MemberFilter.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.siam.package_zuul.filter; - -import com.netflix.zuul.ZuulFilter; -import com.netflix.zuul.context.RequestContext; -import com.netflix.zuul.exception.ZuulException; -import com.siam.package_common.constant.BaseCode; -import com.siam.package_common.entity.BasicResult; -import com.siam.package_common.filter.StoneFilter; -import com.siam.package_common.util.JsonUtils; -import com.siam.package_user.feign.MemberFeignApi; -import com.siam.package_user.auth.cache.MemberSessionManager; -import com.siam.package_user.entity.Member; -import com.siam.package_user.util.TokenUtil; -import com.siam.package_zuul.config.WebMvcConfig; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; -import org.springframework.stereotype.Component; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * 用户过滤器 - * - * @author 暹罗 - */ -@Slf4j -@Component -public class MemberFilter extends ZuulFilter implements StoneFilter { - - @Autowired - private MemberSessionManager memberSessionManager; - - @Autowired - private MemberFeignApi memberFeignApi; - - @Autowired - private WebMvcConfig webMvcConfig; - - /** - * 过滤类型 - * pre:路由之前 - * routing:路由之时 - * post: 路由之后 - * error:发送错误调用 - * @return - */ - @Override - public String filterType() { - return FilterConstants.PRE_TYPE; - } - - /** - * 过滤器执行顺序,当一个请求在同一个阶段存在多个过滤器的时候,多个过滤器执行顺序 - * @return - */ - @Override - public int filterOrder() { - return 0; - } - - /** - * 判断过滤器是否生效 - * @return - */ - @Override - public boolean shouldFilter() { - //此处只需要把当前请求路径 扔到我公共方法中检测是否需要拦截即可 - //通过当前上下文 获取 Request、Response对象 - RequestContext currentContext = RequestContext.getCurrentContext(); - HttpServletRequest request = currentContext.getRequest(); - -// System.out.println("\nuri = " + request.getRequestURI()); -// System.out.println("\nurl = " + request.getRequestURL()); - - return webMvcConfig.matches(request.getRequestURI()); - } - - @Override - public Object run() throws ZuulException { - //通过当前上下文 获取 Request、Response对象 - RequestContext currentContext = RequestContext.getCurrentContext(); - HttpServletRequest request = currentContext.getRequest(); - HttpServletResponse response = currentContext.getResponse(); - - //从header或param里面获取token(暂时这样写,兼容之前前端的写法) - String token = TokenUtil.getToken(); - log.debug("\ntoken = " + token); - if(token == null){ - BasicResult basicResult = new BasicResult(); - basicResult.setSuccess(false); - basicResult.setCode(BaseCode.TOKEN_ERR); - basicResult.setMessage("您暂未登录,请登陆后访问"); - log.debug("\n" + JsonUtils.toJson(basicResult)); - - //token验证失败,不会继续执行后续代码,网关服务直接响应给客户端 - currentContext.setSendZuulResponse(false); - currentContext.setResponseBody(JsonUtils.toJson(basicResult)); -// currentContext.setResponseStatusCode(401); - currentContext.setResponseStatusCode(200); - - return null; - } - - //TODO - 目前如果此处调用出错,该方法是不会继续执行,但是目标接口依旧是返回了数据 - - Member loginMember = memberSessionManager.getSession(token); - if(loginMember != null){ - return null; - } - - BasicResult basicResult = new BasicResult(); - basicResult.setSuccess(false); - basicResult.setCode(BaseCode.TOKEN_ERR); - basicResult.setMessage("您暂未登录,请登陆后访问"); - log.debug("\n" + JsonUtils.toJson(basicResult)); - /*try { - response.getWriter().print(JsonUtils.toJson(basicResult)); - } catch (IOException e) { - e.printStackTrace(); - }*/ - - //token验证失败,不会继续执行后续代码,网关服务直接响应给客户端 - currentContext.setSendZuulResponse(false); - currentContext.setResponseBody(JsonUtils.toJson(basicResult)); -// currentContext.setResponseStatusCode(401); - currentContext.setResponseStatusCode(200); - return null; - } -} \ No newline at end of file diff --git a/siam-zuul/src/main/java/com/siam/package_zuul/filter/MerchantFilter.java b/siam-zuul/src/main/java/com/siam/package_zuul/filter/MerchantFilter.java deleted file mode 100644 index 8db6d40..0000000 --- a/siam-zuul/src/main/java/com/siam/package_zuul/filter/MerchantFilter.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.siam.package_zuul.filter; - -import com.netflix.zuul.ZuulFilter; -import com.netflix.zuul.context.RequestContext; -import com.netflix.zuul.exception.ZuulException; -import com.siam.package_common.constant.BaseCode; -import com.siam.package_common.entity.BasicResult; -import com.siam.package_common.filter.StoneFilter; -import com.siam.package_common.util.JsonUtils; -import com.siam.package_merchant.auth.cache.MerchantSessionManager; -import com.siam.package_merchant.entity.Merchant; -import com.siam.package_user.util.TokenUtil; -import com.siam.package_zuul.config.WebMvcConfig; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; -import org.springframework.stereotype.Component; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * 商家过滤器 - * - * @author 暹罗 - */ -@Slf4j -@Component -public class MerchantFilter extends ZuulFilter implements StoneFilter { - - @Autowired - private MerchantSessionManager adminSessionManager; - - @Autowired - private WebMvcConfig webMvcConfig; - - /** - * 过滤类型 - * pre:路由之前 - * routing:路由之时 - * post: 路由之后 - * error:发送错误调用 - * @return - */ - @Override - public String filterType() { - return FilterConstants.PRE_TYPE; - } - - /** - * 过滤器执行顺序,当一个请求在同一个阶段存在多个过滤器的时候,多个过滤器执行顺序 - * @return - */ - @Override - public int filterOrder() { - return 0; - } - - /** - * 判断过滤器是否生效 - * @return - */ - @Override - public boolean shouldFilter() { - //此处只需要把当前请求路径 扔到我公共方法中检测是否需要拦截即可 - //通过当前上下文 获取 Request、Response对象 - RequestContext currentContext = RequestContext.getCurrentContext(); - HttpServletRequest request = currentContext.getRequest(); - - /*System.out.println("\nuri = " + request.getRequestURI()); - System.out.println("\nurl = " + request.getRequestURL());*/ - - return webMvcConfig.matches(request.getRequestURI()); - } - - @Override - public Object run() throws ZuulException { - //通过当前上下文 获取 Request、Response对象 - RequestContext currentContext = RequestContext.getCurrentContext(); - HttpServletRequest request = currentContext.getRequest(); - HttpServletResponse response = currentContext.getResponse(); - - //从header或param里面获取token(暂时这样写,兼容之前前端的写法) - String token = TokenUtil.getToken(); - log.debug("\ntoken = " + token); - if(token == null){ - BasicResult basicResult = new BasicResult(); - basicResult.setSuccess(false); - basicResult.setCode(BaseCode.TOKEN_ERR); - basicResult.setMessage("您暂未登录,请登陆后访问"); - log.debug("\n" + JsonUtils.toJson(basicResult)); - - //token验证失败,不会继续执行后续代码,网关服务直接响应给客户端 - currentContext.setSendZuulResponse(false); - currentContext.setResponseBody(JsonUtils.toJson(basicResult)); - currentContext.setResponseStatusCode(200); - return null; - } - - //TODO - 目前如果此处调用出错,该方法是不会继续执行,但是目标接口依旧是返回了数据 - Merchant loginMerchant = adminSessionManager.getSession(token); - if(loginMerchant != null){ - return null; - } - - BasicResult basicResult = new BasicResult(); - basicResult.setSuccess(false); - basicResult.setCode(BaseCode.TOKEN_ERR); - basicResult.setMessage("您暂未登录,请登陆后访问"); - log.debug("\n" + JsonUtils.toJson(basicResult)); - /*try { - response.getWriter().print(JsonUtils.toJson(basicResult)); - } catch (IOException e) { - e.printStackTrace(); - }*/ - - //token验证失败,不会继续执行后续代码,网关服务直接响应给客户端 - currentContext.setSendZuulResponse(false); - currentContext.setResponseBody(JsonUtils.toJson(basicResult)); - currentContext.setResponseStatusCode(200); - return null; - } -} \ No newline at end of file diff --git a/siam-zuul/src/main/java/com/siam/package_zuul/filter/RateLimitFilter.java b/siam-zuul/src/main/java/com/siam/package_zuul/filter/RateLimitFilter.java deleted file mode 100644 index 52eab9d..0000000 --- a/siam-zuul/src/main/java/com/siam/package_zuul/filter/RateLimitFilter.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.siam.package_zuul.filter; - -import com.google.common.util.concurrent.RateLimiter; -import com.netflix.zuul.ZuulFilter; -import com.netflix.zuul.context.RequestContext; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.netflix.zuul.filters.Route; -import org.springframework.cloud.netflix.zuul.filters.RouteLocator; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Component; - -import javax.servlet.http.HttpServletRequest; - -@Component -public class RateLimitFilter extends ZuulFilter { - - private static final double URL_RATE_LIMIT = 10.0; // 每分钟允许调用10次 - private static final double IP_RATE_LIMIT = 100.0; // 每分钟允许请求100次 - private static final double USER_GROUP_RATE_LIMIT = 50.0; // 每分钟允许调用50次 - - private final RouteLocator routeLocator; - private final RateLimiter urlRateLimiter; - private final RateLimiter ipRateLimiter; - private final RateLimiter userGroupRateLimiter; - - @Autowired - public RateLimitFilter(RouteLocator routeLocator) { - this.routeLocator = routeLocator; - this.urlRateLimiter = RateLimiter.create(URL_RATE_LIMIT); - this.ipRateLimiter = RateLimiter.create(IP_RATE_LIMIT); - this.userGroupRateLimiter = RateLimiter.create(USER_GROUP_RATE_LIMIT); - } - - @Override - public String filterType() { - return "pre"; - } - - @Override - public int filterOrder() { - return 0; - } - - @Override - public boolean shouldFilter() { - return true; - } - - @Override - public Object run() { - RequestContext context = RequestContext.getCurrentContext(); - HttpServletRequest request = context.getRequest(); - - String url = request.getRequestURI(); - String clientIP = getClientIP(request); - String userId = getUserIdFromRequest(request); - - Route route = routeLocator.getMatchingRoute(url); - - // 对请求的目标URL进行限流 - if (route != null && !urlRateLimiter.tryAcquire()) { - context.setSendZuulResponse(false); - context.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value()); - context.setResponseBody("Request limit exceeded for URL"); - return null; - } - - // 对客户端IP进行限流 - if (!ipRateLimiter.tryAcquire()) { - context.setSendZuulResponse(false); - context.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value()); - context.setResponseBody("Request limit exceeded for IP"); - return null; - } - -// // 对特定用户或用户组进行限流 -// if (!isVIPUser(userId) && !userGroupRateLimiter.tryAcquire()) { -// context.setSendZuulResponse(false); -// context.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value()); -// context.setResponseBody("Request limit exceeded for User/Group"); -// return null; -// } - - return null; - } - - private String getClientIP(HttpServletRequest request) { - String xForwardedForHeader = request.getHeader("X-Forwarded-For"); - if (xForwardedForHeader != null && !xForwardedForHeader.isEmpty()) { - // X-Forwarded-For header can contain a comma-separated list of IPs if multiple proxies are involved. - return xForwardedForHeader.split(",")[0].trim(); - } - return request.getRemoteAddr(); - } - - private String getUserIdFromRequest(HttpServletRequest request) { - // 根据实际情况获取用户ID - return null; - } - - private boolean isVIPUser(String userId) { - // 根据实际情况判断用户是否为VIP - return false; - } -} \ No newline at end of file diff --git a/siam-zuul/src/main/java/com/siam/package_zuul/filter/RateLimitFilter01.java b/siam-zuul/src/main/java/com/siam/package_zuul/filter/RateLimitFilter01.java deleted file mode 100644 index 704994d..0000000 --- a/siam-zuul/src/main/java/com/siam/package_zuul/filter/RateLimitFilter01.java +++ /dev/null @@ -1,55 +0,0 @@ -//package com.siam.package_zuul.filter; -// -//import com.google.common.util.concurrent.RateLimiter; -//import com.netflix.zuul.ZuulFilter; -//import com.netflix.zuul.context.RequestContext; -//import com.netflix.zuul.exception.ZuulException; -//import org.springframework.stereotype.Component; -// -//import java.util.concurrent.TimeUnit; -// -//import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE; -//import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SERVLET_DETECTION_FILTER_ORDER; -// -///** -// * @Classname RateLimiter -// * @Created by Michael -// * @Date 2023/7/13 -// * @Description 限流过滤 -// */ -//@Component -//public class RateLimitFilter01 extends ZuulFilter { -// -// //令牌桶 -// //第一个参数,是总令牌数 -// //第二个参数,简单理解为多久放令牌 -// //第三个参数,是时间单位,即多久投放依次令牌 -// static RateLimiter rateLimiter = RateLimiter.create(8, 2, TimeUnit.SECONDS); -// -// @Override -// public String filterType() { -// return PRE_TYPE; -// } -// -// @Override -// public int filterOrder() { -// return SERVLET_DETECTION_FILTER_ORDER - 1; -// } -// -// @Override -// public boolean shouldFilter() { -// // 这里可以考虑弄个限流开启的开关,开启限流返回true,关闭限流返回false,你懂的。 -// return true; -// } -// -// @Override -// public Object run() throws ZuulException { -// RequestContext context = RequestContext.getCurrentContext(); -// boolean allowed = rateLimiter.tryAcquire(); -// if (!allowed) { -// context.setSendZuulResponse(false); -// context.setResponseStatusCode(501); -// } -// return null; -// } -//} \ No newline at end of file diff --git a/siam-zuul/src/main/java/com/siam/package_zuul/filter/RateLimitFilter02.java b/siam-zuul/src/main/java/com/siam/package_zuul/filter/RateLimitFilter02.java deleted file mode 100644 index a531265..0000000 --- a/siam-zuul/src/main/java/com/siam/package_zuul/filter/RateLimitFilter02.java +++ /dev/null @@ -1,98 +0,0 @@ -//package com.siam.package_zuul.filter; -// -//import com.google.common.util.concurrent.RateLimiter; -//import com.netflix.zuul.ZuulFilter; -//import com.netflix.zuul.context.RequestContext; -//import org.springframework.cloud.netflix.zuul.filters.Route; -//import org.springframework.cloud.netflix.zuul.filters.RouteLocator; -//import org.springframework.http.HttpStatus; -//import org.springframework.stereotype.Component; -// -//import javax.servlet.http.HttpServletRequest; -// -//@Component -//public class RateLimitFilter02 extends ZuulFilter { -// -// // 使用RateLimiter创建令牌桶实例 -// private static final RateLimiter URL_RATE_LIMITER = RateLimiter.create(10); // 每分钟允许调用10次 -// private static final RateLimiter IP_RATE_LIMITER = RateLimiter.create(100); // 每分钟允许请求100次 -// private static final RateLimiter USER_GROUP_RATE_LIMITER = RateLimiter.create(50); // 每分钟允许调用50次 -// -// private final RouteLocator routeLocator; -// -// public RateLimitFilter02(RouteLocator routeLocator) { -// this.routeLocator = routeLocator; -// } -// -// @Override -// public String filterType() { -// return "pre"; -// } -// -// @Override -// public int filterOrder() { -// return 0; -// } -// -// @Override -// public boolean shouldFilter() { -// return true; -// } -// -// @Override -// public Object run() { -// RequestContext context = RequestContext.getCurrentContext(); -// HttpServletRequest request = context.getRequest(); -// -// // 获取请求URL及相关信息 -// String url = request.getRequestURI(); -// String clientIP = getClientIP(request); -// String userId = getUIDFromRequest(request); -// -// Route route = routeLocator.getMatchingRoute(url); -// -// // 对请求的目标URL进行限流 -// if (route != null && !URL_RATE_LIMITER.tryAcquire()) { -// context.setSendZuulResponse(false); -// context.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value()); -// context.setResponseBody("Request limit exceeded for URL"); -// return null; -// } -// -// // 对客户端IP进行限流 -// if (!IP_RATE_LIMITER.tryAcquire()) { -// context.setSendZuulResponse(false); -// context.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value()); -// context.setResponseBody("Request limit exceeded for IP"); -// return null; -// } -// -// // 对特定用户或用户组进行限流 -// if (!isVIPUser(userId) && !USER_GROUP_RATE_LIMITER.tryAcquire()) { -// context.setSendZuulResponse(false); -// context.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value()); -// context.setResponseBody("Request limit exceeded for User/Group"); -// return null; -// } -// -// return null; -// } -// -// // 从HttpServletRequest中获取客户端真实的IP地址 -// private String getClientIP(HttpServletRequest request) { -// // 实现略,根据实际情况获取客户端IP地址 -// return ""; -// } -// -// // 根据请求中的信息判断是否为VIP用户 -// private boolean isVIPUser(String userId) { -// // 实现略,根据实际情况判断用户是否为VIP -// return false; -// } -// -// // 从请求中获取用户ID -// private String getUIDFromRequest(HttpServletRequest request) { -// // 实现略,根据实际情况获取用户ID -// return ""; -// } -//} \ No newline at end of file diff --git a/siam-zuul/src/main/java/com/siam/package_zuul/filter/RequestLogFilter.java b/siam-zuul/src/main/java/com/siam/package_zuul/filter/RequestLogFilter.java deleted file mode 100644 index d5a1f42..0000000 --- a/siam-zuul/src/main/java/com/siam/package_zuul/filter/RequestLogFilter.java +++ /dev/null @@ -1,140 +0,0 @@ -package com.siam.package_zuul.filter; - -import com.alibaba.fastjson.JSON; -import com.netflix.zuul.ZuulFilter; -import com.netflix.zuul.context.RequestContext; -import com.netflix.zuul.http.HttpServletRequestWrapper; -import lombok.extern.slf4j.Slf4j; -import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; -import org.springframework.stereotype.Component; - -import javax.servlet.http.HttpServletRequest; -import java.io.BufferedReader; -import java.io.IOException; -import java.util.Map; - - -/** - * 功能描述:
- * 〈请求参数日志过滤器〉 - * - * @Author:hanxinghua - * @Date: 2020/7/4 - */ -@Slf4j -@Component -public class RequestLogFilter extends ZuulFilter { - - - /** - * 返回过滤器的类型 - * 类型:pre、route、post、error等 - * - * @return - */ - @Override - public String filterType() { - return FilterConstants.PRE_TYPE; - } - - /** - * 返回一个int值来指定同一类型过滤器的执行顺序,不同的过滤器允许返回相同的数字 - * - * @return - */ - @Override - public int filterOrder() { - return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1; - } - - /** - * 返回一个boolean值来判断该过滤器是否需要执行 - * - * @return - */ - @Override - public boolean shouldFilter() { - return true; - } - - /** - * 过滤器的具体逻辑 - * - * @return - */ - @Override - public Object run() { - // 记录PRE_TYPE Filter开始时间戳 - long startTime = System.currentTimeMillis(); - RequestContext.getCurrentContext().set("startTime", startTime); - - RequestContext currentContext = RequestContext.getCurrentContext(); - HttpServletRequest serverHttpRequest = currentContext.getRequest(); - String method = serverHttpRequest.getMethod(); - // 处理跨域发送两次请求,打印两遍日志问题 - if (Constant.OPTIONS.equals(method)) { - return null; - } - log.info("-------------------REQUEST-START-----------------"); - // 记录下请求内容 - log.info("URL: [{}]", serverHttpRequest.getRequestURL().toString()); - log.info("HTTP-METHOD: [{}]", method); - log.info("Content-type: [{}]", serverHttpRequest.getHeader(Constant.CONTENT_TYPE)); - log.info("AUTHORIZATION: [{}]", serverHttpRequest.getHeader(Constant.AUTHORIZATION)); - if (Constant.APP_JSON.equals(serverHttpRequest.getHeader(Constant.CONTENT_TYPE))) { -// //记录application/json时的传参 -// HttpServletRequestWrapper httpServletRequestWrapper = (HttpServletRequestWrapper) serverHttpRequest; -// /*BodyReaderHttpServletRequestWrapper wrapper = (BodyReaderHttpServletRequestWrapper) httpServletRequestWrapper.getRequest();*/ -// BodyReaderHttpServletRequestWrapper wrapper = null; -// try { -// wrapper = new BodyReaderHttpServletRequestWrapper(httpServletRequestWrapper.getRequest()); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// log.info("Request Parameters: \n [{}]", wrapper.getBody()); - - StringBuilder requestBody = new StringBuilder(); - BufferedReader reader = null; - try { - reader = serverHttpRequest.getReader(); - char[] buffer = new char[1024]; - int length; - while ((length = reader.read(buffer)) != -1) { - requestBody.append(buffer, 0, length); - } - } catch (IOException e) { - // 处理异常 - e.printStackTrace(); - } finally { - if (reader != null) { - try { - reader.close(); - } catch (IOException e) { - // 处理异常 - e.printStackTrace(); - } - } - } - log.info("Request Parameters: \n [{}]", requestBody.toString()); - } else { - //记录请求的键值对 - log.info("Request Parameters: \n [{}]", handleInputParameters(serverHttpRequest.getParameterMap())); - } - return null; - - } - - /** - * 处理参数 - * - * @param map - * @return - */ - private String handleInputParameters(Map map){ - if (map.isEmpty()) { - return null; - } - return JSON.toJSONString(map); - } - -} \ No newline at end of file diff --git a/siam-zuul/src/main/java/com/siam/package_zuul/filter/ResponseLogFilter.java b/siam-zuul/src/main/java/com/siam/package_zuul/filter/ResponseLogFilter.java deleted file mode 100644 index 56824a3..0000000 --- a/siam-zuul/src/main/java/com/siam/package_zuul/filter/ResponseLogFilter.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.siam.package_zuul.filter; - -import com.netflix.zuul.ZuulFilter; -import com.netflix.zuul.context.RequestContext; -import lombok.extern.slf4j.Slf4j; -import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; -import org.springframework.stereotype.Component; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.stream.Collectors; - - -/** - * 功能描述:
- * 〈响应参数日志过滤器〉 - * - * @Author:hanxinghua - * @Date: 2020/7/4 - */ -@Slf4j -@Component -public class ResponseLogFilter extends ZuulFilter { - - @Override - public String filterType() { - return FilterConstants.POST_TYPE; - } - - @Override - public int filterOrder() { - return 0; - } - - @Override - public boolean shouldFilter() { - return true; - } - - @Override - public Object run() { - try { - RequestContext currentContext = RequestContext.getCurrentContext(); - HttpServletResponse response = currentContext.getResponse(); - - //需要设置编码格式,否则前端拿到的中文数据会乱码变成???(暂时注释掉,因为加了这两句代码,swagger获取不到返回信息) - response.setCharacterEncoding("UTF-8"); - response.setContentType("application/json;charset=UTF-8"); - - String method = currentContext.getRequest().getMethod(); - // 处理跨域发送两次请求,打印两遍日志问题 - if (Constant.OPTIONS.equals(method)) { - return null; - } - List contentTypeList = currentContext.getZuulResponseHeaders().stream(). - filter(x -> x.first().equals(Constant.CONTENT_TYPE)).map(x -> x.second()).collect(Collectors.toList()); - - if (contentTypeList != null && !contentTypeList.isEmpty()) { - String contentType = contentTypeList.get(0); - log.info("Response Content-type: [{}]", contentType); - - InputStream responseDataStream = currentContext.getResponseDataStream(); - if (responseDataStream != null && contentType !=null && contentType.contains(Constant.APP_JSON)) { - String body = read(responseDataStream); - responseDataStream.close(); - log.info("Response Parameters: \n [{}]", body); - currentContext.setResponseBody(body); //这句话如果注释掉,返回内容直接会被清空 - } - } - - // 获取PRE_TYPE Filter开始时间戳 - long startTime = (Long) RequestContext.getCurrentContext().get("startTime"); - - // 记录POST_TYPE Filter结束时间戳 - long endTime = System.currentTimeMillis(); - - // 计算PRE_TYPE和POST_TYPE Filter之间的请求耗时 - long duration = endTime - startTime; - - log.info("Request Spend Time: [{}]", duration + "ms"); - - } catch (IOException e) { - e.printStackTrace(); - } - log.info("-------------------REQUEST-END-----------------"); - - return null; - } - - private String read(InputStream inputStream) throws IOException { - ByteArrayOutputStream result = new ByteArrayOutputStream(); - byte[] buffer = new byte[1024]; - int length; - while ((length = inputStream.read(buffer)) != -1) { - result.write(buffer, 0, length); - } - return result.toString(StandardCharsets.UTF_8.name()); - } -} \ No newline at end of file diff --git a/siam-zuul/src/main/resources/application-local.yml b/siam-zuul/src/main/resources/application-local.yml deleted file mode 100644 index 349faa7..0000000 --- a/siam-zuul/src/main/resources/application-local.yml +++ /dev/null @@ -1,155 +0,0 @@ -#端口配置 -server: - port: 8080 - #修改tomcat对get请求的参数限制大小(默认为8K) - max-http-header-size: 204800 - -spring: - #redis单例模式 - redis: - host: 127.0.0.1 - password: - port: 6379 - jedis: - pool: - # 连接池中的最大空闲连接个数 - max-idle: 8 - # 连接池中的最小空闲连接个数 - min-idle: 0 - # 连接池最大连接数(使用负值表示没有限制) - max-active: 8 - # 连接池最大阻塞等待时间(使用负值表示没有限制) - max-wait: -1ms - # 连接超时时间(毫秒) - timeout: 600000ms - - #服务别名,注册到注册中心上的名字 - application: - name: zuul-siam - - #允许bean重复定义/允许bean覆盖 - main: - allow-bean-definition-overriding: true - - #邮件相关配置 - mail: - host: smtp.126.com - password: siam1026@163.com - username: siam1026@163.com - properties: - mail: - smtp: - #非必要参数 - auth: true - port: 465 - ssl.enable: true - starttls.enable: true - #必要参数 - timeout: 25000 - socketFactory.class: javax.net.ssl.SSLSocketFactory - socketFactory.port: 465 - -#eureka配置 -eureka: - client: - service-url: - defaultZone: http://127.0.0.1:9000/eureka/ - register-with-eureka: true - fetch-registry: true - instance: - #配置使用ip地址来注册(默认是主机名称) - prefer-ip-address: true - #心跳检测暂时不配置 - -###配置网关信息 -zuul: - routes: - ###定义转发服务规则 - api-user: - ###服务别名 - serviceId: user-siam - ###公开路径,暴露给用户访问的路径 - path: /api-user/** - - api-merchant: - serviceId: merchant-siam - path: /api-merchant/** - - api-rider: - serviceId: rider-siam - path: /api-rider/** - - api-goods: - serviceId: goods-siam - path: /api-goods/** - - api-order: - serviceId: order-siam - path: /api-order/** - - api-promotion: - serviceId: promotion-siam - path: /api-promotion/** - - api-mall: - serviceId: mall-siam - path: /api-mall/** - - api-util: - serviceId: util-siam - path: /api-util/** - - ###配置Zuul超时时间 - host: - ###HTTP连接超时 - connect-timeout-millis: 15000 - ###Socket连接超时 - socket-timeout-millis: 60000 - - #允许向下传递请求头信息 -- 敏感头信息Authorization,Cookie,Set-Cookie默认是不转发的 - sensitive-headers: - -#设置feign客户端超时时间 -ribbon: - #请求处理的超时时间 - ReadTimeout: 120000 - #请求连接的超时时间 - ConnectTimeout: 30000 - -#springboot admin相关配置 -management: - endpoints: - web: - exposure: - include: "*" #'prometheus,health' - exclude: "shutdown" - base-path: /actuator - endpoint: - health: - show-details: ALWAYS - prometheus: - enabled: true - metrics: - export: - prometheus: - enabled: true - step: 1ms - descriptions: true - tags: - # 为指标设置一个Tag,这里设置为应用名,Tag是Prometheus提供的一种能力,从而实现更加灵活的筛选 - application: ${spring.application.name} - # 禁止Actuator监控以下组件连接 - health: - rabbit: - enabled: false - mongo: - enabled: false - elasticsearch: - enabled: false - -#日志配置 -logging: - file: - name: ./logs/${spring.application.name}/log_info.log -path: - log: ./logs/${spring.application.name}/ diff --git a/siam-zuul/src/main/resources/application.yml b/siam-zuul/src/main/resources/application.yml deleted file mode 100644 index c60820e..0000000 --- a/siam-zuul/src/main/resources/application.yml +++ /dev/null @@ -1,5 +0,0 @@ -# 切换正式、测试环境 -spring: - profiles: - #默认连接测试环境 - active: @spring.active@ diff --git a/siam-zuul/src/main/resources/banner.txt b/siam-zuul/src/main/resources/banner.txt deleted file mode 100644 index 7d6e4fe..0000000 --- a/siam-zuul/src/main/resources/banner.txt +++ /dev/null @@ -1,7 +0,0 @@ - . _____ _ __ _ _ - /\\ / ____(_) \ \ \ \ - ( ( )| (___ _ __ _ _ __ ___ \ \ \ \ - \\/ \___ \| |/ _` | '_ ` _ \ ) ) ) ) - ' ____) | | (_| | | | | | | / / / / - ====|_____/|_|\__,_|_| |_| |_|/_/_/_/ - 1.1 \ No newline at end of file diff --git a/siam-zuul/src/main/resources/logback-spring.xml b/siam-zuul/src/main/resources/logback-spring.xml deleted file mode 100644 index a5a0692..0000000 --- a/siam-zuul/src/main/resources/logback-spring.xml +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${CONSOLE_LOG_PATTERN} - utf8 - - - - - - ${log.path}/log_info.log - - - ${log.path}/log_info-%d{yyyy-MM-dd}.log - - ${log.save.time.day} - - - - %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n - - - - - - ${log.path}/log_error.log - - - - ${log.path}/log_error.%d{yyyy-MM-dd}.log - - ${log.save.time.day} - - - ${log.pattern} - - - - ERROR - - ACCEPT - - DENY - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sql/mysql/siam_cloud.sql b/sql/mysql/siam_cloud.sql index 48d33f1..27998f4 100644 --- a/sql/mysql/siam_cloud.sql +++ b/sql/mysql/siam_cloud.sql @@ -3,6 +3,7 @@ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for tb_admin -- ---------------------------- +use siam_cloud; DROP TABLE IF EXISTS `tb_admin`; CREATE TABLE `tb_admin` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id', diff --git a/vue-siam-admin/config/index.js b/vue-siam-admin/config/index.js index 2244f03..4c33481 100644 --- a/vue-siam-admin/config/index.js +++ b/vue-siam-admin/config/index.js @@ -25,13 +25,13 @@ module.exports = { rootPath: '', name: 'siam-admin', http:{ - baseUrl: 'https://api.show.siamit.cn', // production - baseUrl4Test: 'https://api.show.siamit.cn', // production_test - developmentBaseUrl: 'https://api.show.siamit.cn' // development + // baseUrl: 'https://api.show.siamit.cn', // production + // baseUrl4Test: 'https://api.show.siamit.cn', // production_test + // developmentBaseUrl: 'https://api.show.siamit.cn' // development - // baseUrl: 'http://localhost:9020', // production - // baseUrl4Test: 'http://localhost:9020', // production_test - // developmentBaseUrl: 'http://localhost:9020' // development + baseUrl: 'http://127.0.0.1:8081', // production -> 本地 Gateway + baseUrl4Test: 'http://127.0.0.1:8081', // production_test -> 本地 Gateway + developmentBaseUrl: 'http://127.0.0.1:8081' // development -> 本地 Gateway }, oss:{ domain: 'https://siam-hangzhou.oss-cn-hangzhou.aliyuncs.com/' diff --git a/vue-siam-admin/package-lock.json b/vue-siam-admin/package-lock.json index 14509b9..105402b 100644 --- a/vue-siam-admin/package-lock.json +++ b/vue-siam-admin/package-lock.json @@ -9174,7 +9174,8 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "optional": true }, "ansi-styles": { "version": "2.2.1", @@ -9247,6 +9248,7 @@ "version": "0.0.9", "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "optional": true, "requires": { "inherits": "~2.0.0" } @@ -9273,7 +9275,8 @@ "buffer-shims": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", - "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=" + "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=", + "optional": true }, "caseless": { "version": "0.11.0", @@ -9297,7 +9300,8 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "optional": true }, "combined-stream": { "version": "1.0.5", @@ -9326,12 +9330,14 @@ "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "optional": true }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "optional": true }, "cryptiles": { "version": "2.0.5", @@ -9410,7 +9416,8 @@ "extsprintf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", - "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=" + "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=", + "optional": true }, "forever-agent": { "version": "0.6.1", @@ -9432,12 +9439,14 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "optional": true }, "fstream": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.10.tgz", "integrity": "sha1-YE6Kkv4m/9n2+uMDmdSYThqyKCI=", + "optional": true, "requires": { "graceful-fs": "^4.1.2", "inherits": "~2.0.0", @@ -9508,6 +9517,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "optional": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -9520,7 +9530,8 @@ "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "optional": true }, "graceful-readlink": { "version": "1.0.1", @@ -9570,7 +9581,8 @@ "hoek": { "version": "2.16.3", "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "optional": true }, "http-signature": { "version": "1.1.1", @@ -9587,6 +9599,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "optional": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -9595,7 +9608,8 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "optional": true }, "ini": { "version": "1.3.4", @@ -9607,6 +9621,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -9638,7 +9653,8 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "optional": true }, "isstream": { "version": "0.1.2", @@ -9709,6 +9725,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=", + "optional": true, "requires": { "brace-expansion": "^1.0.0" } @@ -9723,6 +9740,7 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "optional": true, "requires": { "minimist": "0.0.8" } @@ -9793,6 +9811,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "optional": true, "requires": { "wrappy": "1" } @@ -9800,7 +9819,8 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "optional": true }, "pinkie": { "version": "2.0.4", @@ -9820,7 +9840,8 @@ "process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "optional": true }, "punycode": { "version": "1.4.1", @@ -9901,6 +9922,7 @@ "version": "2.5.4", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz", "integrity": "sha1-loAAk8vxoMhr2VtGJUZ1NcKd+gQ=", + "optional": true, "requires": { "glob": "^7.0.5" } @@ -9961,6 +9983,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -9970,7 +9993,8 @@ "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "optional": true }, "stringstream": { "version": "0.0.5", @@ -9982,6 +10006,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -10002,6 +10027,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "optional": true, "requires": { "block-stream": "*", "fstream": "^1.0.2", @@ -10080,7 +10106,8 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "optional": true }, "uuid": { "version": "3.0.1", @@ -10109,7 +10136,8 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "optional": true }, "xtend": { "version": "4.0.1", diff --git a/vue-siam-admin/src/pages/shopManage/shopList.vue b/vue-siam-admin/src/pages/shopManage/shopList.vue index c6c15f5..1079efe 100644 --- a/vue-siam-admin/src/pages/shopManage/shopList.vue +++ b/vue-siam-admin/src/pages/shopManage/shopList.vue @@ -373,7 +373,7 @@ editFormSecond: { startDeliveryPrice:'', memberMobile: '', - } + } } }, methods: { @@ -698,7 +698,7 @@ type: 'error' }); } - ) + ) } }); }