From 9400c9985cadaa24bfe9e6ebf3b657bbd803913c Mon Sep 17 00:00:00 2001
From: akun <957746831@qq.com>
Date: Thu, 18 Apr 2024 15:52:07 +0800
Subject: [PATCH] =?UTF-8?q?=E5=8D=8E=E4=B8=BA=E5=BA=94=E7=94=A8=E5=86=85?=
=?UTF-8?q?=E6=94=AF=E4=BB=98=E5=AE=8C=E6=88=90=E4=BC=9A=E5=91=98=E8=AE=A2?=
=?UTF-8?q?=E8=B4=AD=EF=BC=8C=E4=BC=9A=E5=91=98=E4=B8=8E=E5=95=86=E5=93=81?=
=?UTF-8?q?=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 11 +
sf-admin/pom.xml | 8 +
sf-admin/src/main/resources/application.yml | 2 +-
.../order/controller/OrderInfoController.java | 2 -
.../java/com/sf/order/domain/OrderInfo.java | 224 +----
.../sf/order/domain/res/OrderListResVo.java | 18 +
.../sf/order/service/IOrderInfoService.java | 3 +
.../service/impl/OrderInfoServiceImpl.java | 7 +-
.../mapper/order/OrderInfoMapper.xml | 13 +-
sf-payment/pom.xml | 9 +
.../payment/config/HuaweiPaymentConfig.java | 8 +-
.../sf/payment/constant/GoodsConstants.java | 29 +
.../controller/HuaweiPaymentController.java | 4 +-
.../java/com/sf/payment/domain/AuthToken.java | 42 -
.../java/com/sf/payment/domain/AuthUser.java | 73 --
.../domain/HuaweiPurchasesVerifyDTO.java | 36 +-
.../payment/domain/HuaweiQueryResponse.java | 35 +
.../payment/domain/PurchaseOrderPayload.java | 165 ++++
.../payment/domain/SubGroupStatusPayload.java | 48 ++
.../com/sf/payment/domain/SubRenewalInfo.java | 91 +++
.../sf/payment/domain/SubscriptionStatus.java | 68 ++
.../impl/HuaweiPaymentServiceImpl.java | 288 +++++--
.../payment/utils/HuaweiTokenGenerator.java | 43 +
...ey_0ae3e1be-374b-43a5-a297-045addbf76eb.p8 | 6 +
sf-service/pom.xml | 33 +
.../controller/GoodsMessagesController.java | 29 +-
.../com/sf/service}/domain/GoodsMessages.java | 71 +-
.../service}/mapper/GoodsMessagesMapper.java | 10 +-
.../service/IGoodsMessagesService.java | 10 +-
.../impl/GoodsMessagesServiceImpl.java | 21 +-
.../mapper/service}/GoodsMessagesMapper.xml | 246 +++---
sf-ui/src/api/{goods => service}/goods.js | 88 +-
.../views/{goods => service}/goods/index.vue | 771 ++++++++++--------
33 files changed, 1548 insertions(+), 964 deletions(-)
create mode 100644 sf-payment/src/main/java/com/sf/payment/constant/GoodsConstants.java
delete mode 100644 sf-payment/src/main/java/com/sf/payment/domain/AuthToken.java
delete mode 100644 sf-payment/src/main/java/com/sf/payment/domain/AuthUser.java
create mode 100644 sf-payment/src/main/java/com/sf/payment/domain/HuaweiQueryResponse.java
create mode 100644 sf-payment/src/main/java/com/sf/payment/domain/PurchaseOrderPayload.java
create mode 100644 sf-payment/src/main/java/com/sf/payment/domain/SubGroupStatusPayload.java
create mode 100644 sf-payment/src/main/java/com/sf/payment/domain/SubRenewalInfo.java
create mode 100644 sf-payment/src/main/java/com/sf/payment/domain/SubscriptionStatus.java
create mode 100644 sf-payment/src/main/java/com/sf/payment/utils/HuaweiTokenGenerator.java
create mode 100644 sf-payment/src/main/resources/IAPKey_0ae3e1be-374b-43a5-a297-045addbf76eb.p8
create mode 100644 sf-service/pom.xml
rename {sf-admin/src/main/java/com/sf/goods => sf-service/src/main/java/com/sf/service}/controller/GoodsMessagesController.java (83%)
rename {sf-admin/src/main/java/com/sf/goods => sf-service/src/main/java/com/sf/service}/domain/GoodsMessages.java (79%)
rename {sf-admin/src/main/java/com/sf/goods => sf-service/src/main/java/com/sf/service}/mapper/GoodsMessagesMapper.java (87%)
rename {sf-admin/src/main/java/com/sf/goods => sf-service/src/main/java/com/sf/service}/service/IGoodsMessagesService.java (87%)
rename {sf-admin/src/main/java/com/sf/goods => sf-service/src/main/java/com/sf/service}/service/impl/GoodsMessagesServiceImpl.java (80%)
rename {sf-admin/src/main/resources/mapper/goods => sf-service/src/main/resources/mapper/service}/GoodsMessagesMapper.xml (76%)
rename sf-ui/src/api/{goods => service}/goods.js (76%)
rename sf-ui/src/views/{goods => service}/goods/index.vue (67%)
diff --git a/pom.xml b/pom.xml
index a82b5d6..9c6a7a9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -174,6 +174,17 @@
${sf.version}
+
+ com.smarterFramework
+ sf-payment
+ ${sf.version}
+
+
+
+ com.smarterFramework
+ sf-service
+ ${sf.version}
+
com.smarterFramework
diff --git a/sf-admin/pom.xml b/sf-admin/pom.xml
index 49f0926..6a68f81 100644
--- a/sf-admin/pom.xml
+++ b/sf-admin/pom.xml
@@ -71,7 +71,15 @@
sf-order
+
+ com.smarterFramework
+ sf-payment
+
+
+ com.smarterFramework
+ sf-service
+
diff --git a/sf-admin/src/main/resources/application.yml b/sf-admin/src/main/resources/application.yml
index 843f1c4..d953204 100644
--- a/sf-admin/src/main/resources/application.yml
+++ b/sf-admin/src/main/resources/application.yml
@@ -18,7 +18,7 @@ sf:
# 开发环境配置
server:
# 服务器的HTTP端口,默认为8080
- port: 7781
+ port: 80
servlet:
# 应用的访问路径
context-path: /
diff --git a/sf-order/src/main/java/com/sf/order/controller/OrderInfoController.java b/sf-order/src/main/java/com/sf/order/controller/OrderInfoController.java
index 21f3db2..2011062 100644
--- a/sf-order/src/main/java/com/sf/order/controller/OrderInfoController.java
+++ b/sf-order/src/main/java/com/sf/order/controller/OrderInfoController.java
@@ -3,10 +3,8 @@ package com.sf.order.controller;
import com.sf.common.annotation.Log;
import com.sf.common.core.controller.BaseController;
import com.sf.common.core.domain.AjaxResult;
-import com.sf.common.core.domain.entity.SysUser;
import com.sf.common.core.page.TableDataInfo;
import com.sf.common.enums.BusinessType;
-import com.sf.common.utils.SecurityUtils;
import com.sf.common.utils.poi.ExcelUtil;
import com.sf.order.domain.OrderInfo;
import com.sf.order.domain.dto.OrderCreateDto;
diff --git a/sf-order/src/main/java/com/sf/order/domain/OrderInfo.java b/sf-order/src/main/java/com/sf/order/domain/OrderInfo.java
index 6785f83..889350d 100644
--- a/sf-order/src/main/java/com/sf/order/domain/OrderInfo.java
+++ b/sf-order/src/main/java/com/sf/order/domain/OrderInfo.java
@@ -3,6 +3,7 @@ package com.sf.order.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sf.common.annotation.Excel;
import com.sf.common.core.domain.BaseEntity;
+import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@@ -14,6 +15,7 @@ import java.util.Date;
* @author ztzh
* @date 2024-04-09
*/
+@Data
public class OrderInfo extends BaseEntity {
private static final long serialVersionUID = 1L;
@@ -26,7 +28,7 @@ public class OrderInfo extends BaseEntity {
* 订单编号
*/
@Excel(name = "订单编号")
- private String orderNo;
+ private Long orderNo;
/**
* 订单状态: 0:待支付 1:已付款待发货 2:配送中 3:待取货 4:支付超时系统结束 5:客户自主取消 6:已完成
@@ -155,209 +157,27 @@ public class OrderInfo extends BaseEntity {
@Excel(name = "减免金额(优惠券抵扣)")
private Long reductionAmout;
- public void setId(Long id) {
- this.id = id;
- }
+ /**
+ * * 商品数量
+ */
+ private Integer goodsCount;
+ /**
+ * * 商品类型。
+ * * • 0:消耗型商品
+ * * • 1:非消耗型商品
+ * * • 2:自动续期订阅商品
+ */
+ private Integer goodsType;
- public Long getId() {
- return id;
- }
+ /**
+ * 商品单价
+ */
+ private Long goodsPrice;
- public void setOrderNo(String orderNo) {
- this.orderNo = orderNo;
- }
+ /**
+ * 商品编号
+ */
+ private String goodsCode;
- public String getOrderNo() {
- return orderNo;
- }
- public void setOrderStatus(Long orderStatus) {
- this.orderStatus = orderStatus;
- }
-
- public Long getOrderStatus() {
- return orderStatus;
- }
-
- public void setPayType(Long payType) {
- this.payType = payType;
- }
-
- public Long getPayType() {
- return payType;
- }
-
- public void setPayChannel(Long payChannel) {
- this.payChannel = payChannel;
- }
-
- public Long getPayChannel() {
- return payChannel;
- }
-
- public void setOrderAmt(Long orderAmt) {
- this.orderAmt = orderAmt;
- }
-
- public Long getOrderAmt() {
- return orderAmt;
- }
-
- public void setFreightAmt(Long freightAmt) {
- this.freightAmt = freightAmt;
- }
-
- public Long getFreightAmt() {
- return freightAmt;
- }
-
- public void setPayAmt(Long payAmt) {
- this.payAmt = payAmt;
- }
-
- public Long getPayAmt() {
- return payAmt;
- }
-
- public void setReallyAmt(Long reallyAmt) {
- this.reallyAmt = reallyAmt;
- }
-
- public Long getReallyAmt() {
- return reallyAmt;
- }
-
- public void setReceiveType(Long receiveType) {
- this.receiveType = receiveType;
- }
-
- public Long getReceiveType() {
- return receiveType;
- }
-
- public void setGoodsId(Long goodsId) {
- this.goodsId = goodsId;
- }
-
- public Long getGoodsId() {
- return goodsId;
- }
-
- public void setBusinessId(Long businessId) {
- this.businessId = businessId;
- }
-
- public Long getBusinessId() {
- return businessId;
- }
-
- public void setReceiveAddrId(Long receiveAddrId) {
- this.receiveAddrId = receiveAddrId;
- }
-
- public Long getReceiveAddrId() {
- return receiveAddrId;
- }
-
- public void setPayTime(Date payTime) {
- this.payTime = payTime;
- }
-
- public Date getPayTime() {
- return payTime;
- }
-
- public void setCreateUserId(Long createUserId) {
- this.createUserId = createUserId;
- }
-
- public Long getCreateUserId() {
- return createUserId;
- }
-
- public void setUpdateUserId(Long updateUserId) {
- this.updateUserId = updateUserId;
- }
-
- public Long getUpdateUserId() {
- return updateUserId;
- }
-
- public void setIsDelete(Long isDelete) {
- this.isDelete = isDelete;
- }
-
- public Long getIsDelete() {
- return isDelete;
- }
-
- public void setTrackNo(String trackNo) {
- this.trackNo = trackNo;
- }
-
- public String getTrackNo() {
- return trackNo;
- }
-
- public void setOrderType(Long orderType) {
- this.orderType = orderType;
- }
-
- public Long getOrderType() {
- return orderType;
- }
-
- public void setOutOrderNo(String outOrderNo) {
- this.outOrderNo = outOrderNo;
- }
-
- public String getOutOrderNo() {
- return outOrderNo;
- }
-
- public void setPayData(String payData) {
- this.payData = payData;
- }
-
- public String getPayData() {
- return payData;
- }
-
- public void setReductionAmout(Long reductionAmout) {
- this.reductionAmout = reductionAmout;
- }
-
- public Long getReductionAmout() {
- return reductionAmout;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
- .append("id", getId())
- .append("orderNo", getOrderNo())
- .append("orderStatus", getOrderStatus())
- .append("payType", getPayType())
- .append("payChannel", getPayChannel())
- .append("orderAmt", getOrderAmt())
- .append("freightAmt", getFreightAmt())
- .append("payAmt", getPayAmt())
- .append("reallyAmt", getReallyAmt())
- .append("receiveType", getReceiveType())
- .append("goodsId", getGoodsId())
- .append("businessId", getBusinessId())
- .append("receiveAddrId", getReceiveAddrId())
- .append("createTime", getCreateTime())
- .append("payTime", getPayTime())
- .append("createUserId", getCreateUserId())
- .append("updateUserId", getUpdateUserId())
- .append("isDelete", getIsDelete())
- .append("updateTime", getUpdateTime())
- .append("trackNo", getTrackNo())
- .append("orderType", getOrderType())
- .append("outOrderNo", getOutOrderNo())
- .append("payData", getPayData())
- .append("reductionAmout", getReductionAmout())
- .toString();
- }
}
diff --git a/sf-order/src/main/java/com/sf/order/domain/res/OrderListResVo.java b/sf-order/src/main/java/com/sf/order/domain/res/OrderListResVo.java
index 6bea013..1fe724d 100644
--- a/sf-order/src/main/java/com/sf/order/domain/res/OrderListResVo.java
+++ b/sf-order/src/main/java/com/sf/order/domain/res/OrderListResVo.java
@@ -71,5 +71,23 @@ public class OrderListResVo {
*/
private Integer goodsCount;
+ /**
+ * 商品价格
+ */
+ private Long goodsPrice;
+
+ /**
+ * * 商品类型。
+ * * • 0:消耗型商品
+ * * • 1:非消耗型商品
+ * * • 2:自动续期订阅商品
+ */
+ private Integer goodsType;
+
+ /**
+ * 商品编码
+ */
+ private String goodsCode;
+
}
diff --git a/sf-order/src/main/java/com/sf/order/service/IOrderInfoService.java b/sf-order/src/main/java/com/sf/order/service/IOrderInfoService.java
index 16d34ef..9904bb6 100644
--- a/sf-order/src/main/java/com/sf/order/service/IOrderInfoService.java
+++ b/sf-order/src/main/java/com/sf/order/service/IOrderInfoService.java
@@ -72,4 +72,7 @@ public interface IOrderInfoService
void orderPay(Long orderId);
OrderInfo selectOrderInfoByOrderNo(String orderNo);
+
+ void insertOrder(OrderInfo orderInfo);
+
}
diff --git a/sf-order/src/main/java/com/sf/order/service/impl/OrderInfoServiceImpl.java b/sf-order/src/main/java/com/sf/order/service/impl/OrderInfoServiceImpl.java
index 24a723a..c628cfa 100644
--- a/sf-order/src/main/java/com/sf/order/service/impl/OrderInfoServiceImpl.java
+++ b/sf-order/src/main/java/com/sf/order/service/impl/OrderInfoServiceImpl.java
@@ -62,7 +62,7 @@ public class OrderInfoServiceImpl implements IOrderInfoService {
@Override
public Long createOrder(OrderCreateDto orderCreateDto) {
OrderInfo orderInfo = new OrderInfo();
- orderInfo.setOrderNo(snowflakeIdWorker.nextId() + "");
+ orderInfo.setOrderNo(snowflakeIdWorker.nextId());
orderInfo.setPayType(1L);
orderInfo.setReceiveType(0L);
orderInfo.setOrderStatus(0L);
@@ -113,6 +113,11 @@ public class OrderInfoServiceImpl implements IOrderInfoService {
return orderInfoMapper.selectOrderInfoByOrderNo(orderNo);
}
+ @Override
+ public void insertOrder(OrderInfo orderInfo) {
+ orderInfoMapper.insertOrderInfo(orderInfo);
+ }
+
/**
* 批量删除订单基础信息
*
diff --git a/sf-order/src/main/resources/mapper/order/OrderInfoMapper.xml b/sf-order/src/main/resources/mapper/order/OrderInfoMapper.xml
index 51117d1..bab236b 100644
--- a/sf-order/src/main/resources/mapper/order/OrderInfoMapper.xml
+++ b/sf-order/src/main/resources/mapper/order/OrderInfoMapper.xml
@@ -42,13 +42,16 @@
+
+
+
select id, order_no, order_status, pay_type, pay_channel, order_amt, freight_amt, pay_amt, really_amt, receive_type, goods_id, business_id, receive_addr_id, create_time, pay_time, create_user_id, update_user_id, is_delete, update_time, track_no, order_type, out_order_no, pay_data, reduction_amout from Order_info
- SELECT a.id,a.order_no,a.order_status,a.order_amt,a.pay_time,a.count as goods_count,a.subscription_cancellation_time,b.product_title,b.product_picture,b.product_desc,b.goods_spec
+ SELECT a.id,a.order_no,a.order_status,a.order_amt,a.pay_time,a.goods_count,a.subscription_cancellation_time,a.goods_type,a.goods_price,a.goods_code,b.product_title,b.product_picture,b.product_desc,b.goods_spec
FROM Order_info a LEFT JOIN GOODS_MESSAGES b ON a.goods_id = b.id
@@ -124,6 +127,10 @@
out_order_no,
pay_data,
reduction_amout,
+ goods_count,
+ goods_type,
+ goods_price,
+ goods_code,
#{id},
@@ -150,6 +157,10 @@
#{outOrderNo},
#{payData},
#{reductionAmout},
+ #{goodsCount},
+ #{goodsType},
+ #{goodsPrice},
+ #{goodsCode},
diff --git a/sf-payment/pom.xml b/sf-payment/pom.xml
index b8bc13d..680816a 100644
--- a/sf-payment/pom.xml
+++ b/sf-payment/pom.xml
@@ -30,11 +30,20 @@
com.smarterFramework
sf-order
+
+ com.smarterFramework
+ sf-service
+
org.bouncycastle
bcprov-jdk18on
1.73
+
+ com.auth0
+ java-jwt
+ 4.4.0
+
diff --git a/sf-payment/src/main/java/com/sf/payment/config/HuaweiPaymentConfig.java b/sf-payment/src/main/java/com/sf/payment/config/HuaweiPaymentConfig.java
index e52acb7..f9d76f5 100644
--- a/sf-payment/src/main/java/com/sf/payment/config/HuaweiPaymentConfig.java
+++ b/sf-payment/src/main/java/com/sf/payment/config/HuaweiPaymentConfig.java
@@ -16,7 +16,7 @@ import org.springframework.context.annotation.Configuration;
public class HuaweiPaymentConfig {
/**
- * 客户端id:对应各平台的appKey
+ * 客户端id:(oauth用)
*/
@Value("${huawei.payment.clientId:110693217}")
private String clientId;
@@ -27,5 +27,11 @@ public class HuaweiPaymentConfig {
@Value("${huawei.payment.clientSecret:1410c01bc71c7ba587175ae79e500137c70945acc1416a38127cf98a09a6f8ba}")
private String clientSecret;
+ /**
+ * 应用id
+ */
+ @Value("${huawei.payment.appId:5765880207854169373}")
+ private String appId;
+
}
diff --git a/sf-payment/src/main/java/com/sf/payment/constant/GoodsConstants.java b/sf-payment/src/main/java/com/sf/payment/constant/GoodsConstants.java
new file mode 100644
index 0000000..53b8b1c
--- /dev/null
+++ b/sf-payment/src/main/java/com/sf/payment/constant/GoodsConstants.java
@@ -0,0 +1,29 @@
+package com.sf.payment.constant;
+
+import io.jsonwebtoken.Claims;
+
+/**
+ * 商品信息
+ *
+ * @author zoukun
+ */
+public class GoodsConstants {
+ /**
+ * 商品类型。
+ * • 0:消耗型商品
+ */
+ public static final Integer GOODS_TYPE_CONSUMABLE = 0;
+
+ /**
+ * 商品类型。
+ * • 1:非消耗型商品
+ */
+ public static final Integer GOODS_TYPE_NON_CONSUMABLE = 1;
+
+ /**
+ * 商品类型。
+ * • 2:自动续期订阅商品
+ */
+ public static final Integer GOODS_TYPE_AUTOMATIC_RENEWAL_SUBSCRIPTION = 2;
+
+}
diff --git a/sf-payment/src/main/java/com/sf/payment/controller/HuaweiPaymentController.java b/sf-payment/src/main/java/com/sf/payment/controller/HuaweiPaymentController.java
index baa770d..74650cc 100644
--- a/sf-payment/src/main/java/com/sf/payment/controller/HuaweiPaymentController.java
+++ b/sf-payment/src/main/java/com/sf/payment/controller/HuaweiPaymentController.java
@@ -2,11 +2,13 @@ package com.sf.payment.controller;
import com.alibaba.fastjson2.JSONObject;
import com.sf.common.core.domain.AjaxResult;
+import com.sf.payment.constant.GoodsConstants;
import com.sf.payment.domain.HuaweiPaymentCallback;
import com.sf.payment.domain.HuaweiPurchasesVerifyDTO;
import com.sf.payment.service.IHuaweiPaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -36,7 +38,7 @@ public class HuaweiPaymentController {
/**
* 华为购买验证
*/
- @RequestMapping("/huawei/purchases/verify")
+ @PostMapping("/huawei/purchases/verify")
public AjaxResult purchasesVerify(@Validated @RequestBody HuaweiPurchasesVerifyDTO verifyDTO) {
log.info("进入/huawei/purchases/tokens/verify: params:" + JSONObject.toJSONString(verifyDTO));
huaweiPaymentService.purchasesVerify(verifyDTO);
diff --git a/sf-payment/src/main/java/com/sf/payment/domain/AuthToken.java b/sf-payment/src/main/java/com/sf/payment/domain/AuthToken.java
deleted file mode 100644
index 20bd856..0000000
--- a/sf-payment/src/main/java/com/sf/payment/domain/AuthToken.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.sf.payment.domain;
-
-import lombok.*;
-
-import java.io.Serializable;
-
-/**
- * 授权所需的token
- *
- * @author zoukun
- */
-@Getter
-@Setter
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class AuthToken implements Serializable {
- private String accessToken;
- private int expireIn;
- private String refreshToken;
- private int refreshTokenExpireIn;
- private String uid;
- private String openId;
- private String accessCode;
- private String unionId;
-
- /**
- * 华为返回 生成的Access Token中包含的scope。
- */
- private String scope;
-
- /**
- * 华为返回 固定返回Bearer,标识返回Access Token的类型
- */
- private String tokenType;
-
- /**
- * 华为返回 返回JWT格式数据,包含用户基本帐号、用户邮箱等信息。
- * 参照https://developer.huawei.com/consumer/cn/doc/HMSCore-References/account-verify-id-token_hms_reference-0000001050050577#section3142132691914
- */
- private String idToken;
-}
diff --git a/sf-payment/src/main/java/com/sf/payment/domain/AuthUser.java b/sf-payment/src/main/java/com/sf/payment/domain/AuthUser.java
deleted file mode 100644
index 03eaa4b..0000000
--- a/sf-payment/src/main/java/com/sf/payment/domain/AuthUser.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.sf.payment.domain;
-
-import com.alibaba.fastjson2.JSONObject;
-import lombok.*;
-
-import java.io.Serializable;
-
-/**
- * 授权成功后的用户信息,根据授权平台的不同,获取的数据完整性也不同
- *
- * @author zoukun
- */
-@Getter
-@Setter
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class AuthUser implements Serializable {
- /**
- * 用户第三方系统的唯一id。
- */
- private String uuid;
- /**
- * 用户名
- */
- private String username;
- /**
- * 用户昵称
- */
- private String nickname;
- /**
- * 用户头像
- */
- private String avatar;
- /**
- * 用户网址
- */
- private String blog;
- /**
- * 所在公司
- */
- private String company;
- /**
- * 位置
- */
- private String location;
- /**
- * 用户邮箱
- */
- private String email;
- /**
- * 用户手机号
- */
- private String mobileNumber;
- /**
- * 用户备注(各平台中的用户个人介绍)
- */
- private String remark;
- /**
- * 用户来源
- */
- private String source;
- /**
- * 用户授权的token信息
- */
- private AuthToken token;
- /**
- * 第三方平台返回的原始用户信息
- */
- private JSONObject rawUserInfo;
-
-
-}
diff --git a/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyDTO.java b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyDTO.java
index 563f879..49a250c 100644
--- a/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyDTO.java
+++ b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyDTO.java
@@ -21,31 +21,33 @@ public class HuaweiPurchasesVerifyDTO implements Serializable {
/**
- * 商品类别,取值包括:
- *
- * 0:消耗型商品
- * 1:非消耗型商品
- * 2:订阅型商品
+ * 商品类型。
+ * • 0:消耗型商品
+ * • 1:非消耗型商品
+ * • 2:自动续期订阅商品
*/
@NotNull
- private Integer kind;
+ private Integer type;
/**
- * 待下发商品的购买Token,发起购买和查询待消费商品信息时均会返回purchaseToken参数。
+ * 包含订单信息的JWS格式数据。
+ * 可参见对返回结果验签
+ * 解码验签获取相关购买数据的JSON字符串,
+ * 其包含的参数请参见PurchaseOrderPayload。
*/
- @NotBlank(message = "待下发商品的购买Token不能为空")
- private String purchaseToken;
+ private String jwsPurchaseOrder;
/**
- * 待下发商品ID。商品ID来源于您在AppGallery Connect中配置商品信息时设置的商品ID。
+ * 包含订阅状态信息的
+ * JWS格式数据。
+ * 可参见对返回结果验签
+ * 解码验签获取相关订阅状态
+ * 信息的JSON字符串,
+ * 其包含的参数请参见
+ * SubGroupStatusPayload。
*/
- @NotBlank(message = "待下发商品ID不能为空")
- private String productId;
+ private String jwsSubscriptionStatus;
+
- /**
- * 订单号
- */
- @NotBlank(message = "订单号不能为空")
- private String orderNo;
}
diff --git a/sf-payment/src/main/java/com/sf/payment/domain/HuaweiQueryResponse.java b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiQueryResponse.java
new file mode 100644
index 0000000..4814e9f
--- /dev/null
+++ b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiQueryResponse.java
@@ -0,0 +1,35 @@
+package com.sf.payment.domain;
+
+import lombok.Data;
+
+/**
+ * 功能描述:
+ *
+ * @author a_kun
+ * @date 2024/4/17 14:41
+ */
+@Data
+public class HuaweiQueryResponse {
+
+ /**
+ * 返回码。
+ * • 0:成功。
+ * • 其他:失败,具体请参见错误码
+ */
+ private String responseCode;
+
+ /**
+ * 响应描述。
+ */
+ private String responseMessage;
+
+ /**
+ * 包含已购订单相关状态信息的JWS格式数据。可参见对返回结果验签解码验签获取相关订单状态信息的JSON字符串,其包含的参数具体请参见表PurchaseOrderPayload说明。
+ */
+ private String jwsPurchaseOrder;
+
+ /**
+ * 包含已购订阅相关状态信息的JWS格式数据。可参见对返回结果验签解码验签获取相关订阅状态信息的JSON字符串,其包含的参数请参见SubGroupStatusPayload
+ */
+ private String jwsSubGroupStatus;
+}
diff --git a/sf-payment/src/main/java/com/sf/payment/domain/PurchaseOrderPayload.java b/sf-payment/src/main/java/com/sf/payment/domain/PurchaseOrderPayload.java
new file mode 100644
index 0000000..8c8fab2
--- /dev/null
+++ b/sf-payment/src/main/java/com/sf/payment/domain/PurchaseOrderPayload.java
@@ -0,0 +1,165 @@
+package com.sf.payment.domain;
+
+import lombok.Data;
+
+/**
+ * 功能描述:
+ * 订单信息模型,支持消耗型商品、非消耗型商品和自动续期订阅商品。
+ * @author a_kun
+ * @date 2024/4/16 15:29
+ */
+@Data
+public class PurchaseOrderPayload {
+
+ /**
+ * 具体一笔订单中对应的购买订单号ID。
+ */
+ private String purchaseOrderId;
+
+ /**
+ * 购买token,
+ * 在购买消耗型/非消耗型商品场景中与具体购买订单一一对应,
+ * 在自动续期订阅商品场景中与订阅ID一一对应。
+ */
+ private String purchaseToken;
+
+ /**
+ * 应用ID。
+ */
+ private String applicationId;
+
+ /**
+ * 商品ID。每种商品必须有唯一的ID,由应用在PMS中维护,或者应用发起购买时传入。
+ * 说明
+ * 为避免资金损失,您在对支付结果验签成功后,必须对其进行校验。
+ */
+ private String productId;
+
+ /**
+ * 商品类型。具体取值如下:
+ * • 0:消耗型商品
+ * • 1:非消耗型商品
+ * • 2:自动续期订阅商品
+ */
+ private Integer productType;
+
+ /**
+ * 购买时间,UTC时间戳,以毫秒为单位。
+ * 如果没有完成购买,则没有值。
+ */
+ private Long purchaseTime;
+
+ /**
+ * 发货状态。具体取值如下:
+ * • 1:已发货
+ * • 2:未发货
+ */
+ private Integer finishStatus;
+
+ /**
+ * 价格,单位:分。
+ * 实际价格*100以后的值。商品实际价格精确到小数点后2位,例如此参数值为501,则表示商品实际价格为5.01。
+ */
+ private Long price;
+
+ /**
+ * 用定价货币的币种,请参见ISO 4217标准。
+ * 说明
+ * 为避免资金损失,您在对支付结果验签成功后,必须对其进行校验。
+ */
+ private String currency;
+
+ /**
+ * 商户侧保留信息,由您在调用支付接口时传入。
+ */
+ private String developerPayload;
+
+ /**
+ * 购买订单撤销原因。
+ * • 0:其他
+ * • 1:用户遇到问题退款
+ */
+ private Integer purchaseOrderRevocationReasonCode;
+
+ /**
+ * 购买订单撤销时间,
+ * UTC时间戳,以毫秒为单位。
+ */
+ private Long revocationTime;
+
+ /**
+ * 优惠类型。
+ * • 1:推介促销
+ */
+ private Integer offerTypeCode;
+
+ /**
+ * 优惠ID。
+ */
+ private String offerId;
+
+ /**
+ * 国家/地区码,用于区分国家/地区信息,请参见ISO 3166
+ */
+ private String countryCode;
+
+ /**
+ * 签名时间,UTC时间戳,以毫秒为单位。
+ */
+ private Long signedTime;
+
+ // 以下参数只在自动续期订阅商品场景返回
+
+
+ /**
+ * 订阅连续购买段的唯一ID,
+ * 当用户切换商品不会重置此ID。
+ */
+ private String subGroupGenerationId;
+
+ /**
+ * 订阅连续购买段的唯一ID,
+ * 当用户切换订阅商品时
+ * 此订阅ID会发生改变。
+ */
+ private String subscriptionId;
+
+ /**
+ * 订阅组ID。
+ */
+ private String subGroupId;
+
+ /**
+ * 此次购买的有效周期,
+ * 采用ISO 8601格式。
+ * 例如:P1W表示一周,
+ * P1M表示一个月。
+ */
+ private String duration;
+
+ /**
+ * 订阅周期段类型。
+ * • 0:正常周期段
+ * • 1:延期周期段
+ */
+ private Integer durationTypeCode;
+
+ /*
+ ISO 8601的时间持续期限表示
+ 在ISO 8601中,时间持续期限的表示采用了一种简洁而明确的格式,例如 “P10D”,其中 “P” 表示周期(Period),后面的数字表示周期的长度,而末尾的字母表示周期的单位。这种表示法主要用于描述时间段的长度,而不关注具体的时刻。
+ “P” 表示周期(Period): 此字母指示接下来的时间表示将是一个时间段的描述,而非具体的日期或时刻。
+ 后面的数字: 这个数字表示时间段的长度,可以是整数或小数。它指示了在时间单位内的周期数量。
+ 末尾的字母表示周期的单位: 在 “P10D” 中,末尾的 “D” 表示周期的单位是天(Days)。ISO 8601定义了多种可能的时间单位,包括:
+ Y(年): 表示年份,例如 “P2Y” 表示2年的时间段。
+ M(月): 表示月份,例如 “P3M” 表示3个月的时间段。
+ W(周): 表示周数,例如 “P1W” 表示1周的时间段。
+ D(日): 表示天数,例如 “P10D” 表示10天的时间段。
+ T(时间分隔符): 如果时间段中包含了时间信息,日期和时间之间用 “T” 分隔,例如 “P1DT12H” 表示1天12小时的时间段。
+ H(小时)、M(分钟)、S(秒): 用于表示时、分、秒的时间段长度,例如 “PT2H30M” 表示2小时30分钟的时间段。
+ 示例:
+ “P1Y”: 表示1年的时间段。
+ “P3M”: 表示3个月的时间段。
+ “P2W”: 表示2周的时间段。
+ “P4DT6H30M”: 表示4天6小时30分钟的时间段。
+ */
+}
diff --git a/sf-payment/src/main/java/com/sf/payment/domain/SubGroupStatusPayload.java b/sf-payment/src/main/java/com/sf/payment/domain/SubGroupStatusPayload.java
new file mode 100644
index 0000000..7fcad45
--- /dev/null
+++ b/sf-payment/src/main/java/com/sf/payment/domain/SubGroupStatusPayload.java
@@ -0,0 +1,48 @@
+package com.sf.payment.domain;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 功能描述:
+ * 已购订阅相关状态信息
+ * @author a_kun
+ * @date 2024/4/16 15:29
+ */
+@Data
+public class SubGroupStatusPayload {
+
+ /**
+ * 应用ID。
+ */
+ private String applicationId;
+
+ /**
+ * 应用包名。
+ */
+ private String packageName;
+
+ /**
+ * 订阅组ID。
+ */
+ private String subGroupId;
+
+ /**
+ * 订阅组中最后生效的
+ * 订阅状态
+ * SubscriptionStatus,
+ * 比如A切换B,B切换C,
+ * 此处是C的订阅状态。
+ */
+ private SubscriptionStatus lastSubscriptionStatus;
+
+ /**
+ * 订阅组最近生效的
+ * 历史订阅状态
+ * SubscriptionStatus的列表,比如A切换B,B切换C,这里包含C,B,A三个订阅状态信息。
+ */
+ private List historySubscriptionStatusList;
+
+
+}
diff --git a/sf-payment/src/main/java/com/sf/payment/domain/SubRenewalInfo.java b/sf-payment/src/main/java/com/sf/payment/domain/SubRenewalInfo.java
new file mode 100644
index 0000000..cfff488
--- /dev/null
+++ b/sf-payment/src/main/java/com/sf/payment/domain/SubRenewalInfo.java
@@ -0,0 +1,91 @@
+package com.sf.payment.domain;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 功能描述:
+ * 当前订阅最新的未来扣费计划
+ * @author a_kun
+ * @date 2024/4/16 15:29
+ */
+@Data
+public class SubRenewalInfo {
+
+ /**
+ * 订阅连续购买段的唯一ID,
+ * 当用户切换商品不会重置此ID。
+ */
+ private String subGroupGenerationId;
+
+ /**
+ * 下周期生效场景下,下期将续期的商品ID。
+ */
+ private String nextRenewPeriodProductId;
+
+ /**
+ * 当前生效的商品ID。
+ */
+ private String productId;
+
+ /**
+ * 自动续期状态。
+ * • 0:关闭
+ * • 1:打开
+ */
+ private Integer autoRenewStatusCode;
+
+ /**
+ * 系统是否还在尝试扣费。
+ * • true:是
+ * • false:否
+ */
+ private Boolean hasInBillingRetryPeriod;
+
+ /**
+ * 目前涨价状态码。
+ * • 1:用户暂未同意涨价
+ * • 2:用户已同意涨价
+ */
+ private Integer priceIncreaseStatusCode;
+
+ /**
+ * 优惠类型。
+ * • 1:推介促销
+ */
+ private Integer offerTypeCode;
+
+ /**
+ * 优惠ID。
+ */
+ private String offerId;
+
+ /**
+ * 下期续费价格,单位:分,取消订阅场景下不返回。
+ */
+ private String renewalPrice;
+
+ /**
+ * 币种。
+ */
+ private String currency;
+
+ /**
+ * 续期时间,UTC时间戳,以毫秒为单位。。
+ */
+ private Long renewalTime;
+
+ /**
+ * 订阅续期失败的原因。
+ * • 1:用户取消
+ * • 2:商品无效
+ * • 3:签约无效
+ * • 4:扣费异常
+ * • 5:用户不同意涨价
+ * • 6:未知
+ */
+ private String expirationIntent;
+
+
+}
diff --git a/sf-payment/src/main/java/com/sf/payment/domain/SubscriptionStatus.java b/sf-payment/src/main/java/com/sf/payment/domain/SubscriptionStatus.java
new file mode 100644
index 0000000..8adb949
--- /dev/null
+++ b/sf-payment/src/main/java/com/sf/payment/domain/SubscriptionStatus.java
@@ -0,0 +1,68 @@
+package com.sf.payment.domain;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 功能描述:
+ * 订阅组中最后生效的订阅状态
+ * @author a_kun
+ * @date 2024/4/16 15:29
+ */
+@Data
+public class SubscriptionStatus {
+
+ /**
+ * 订阅连续购买段的唯一ID,
+ * 当用户切换商品不会重置此ID。
+ */
+ private String subGroupGenerationId;
+
+ /**
+ * 订阅连续购买段的唯一ID,
+ * 当用户切换订阅商品时
+ * 此订阅ID会发生改变。
+ */
+ private String subscriptionId;
+
+ /**
+ * 购买token,
+ * 在购买消耗型/非消耗型商品场景中与具体购买订单一一对应,
+ * 在自动续期订阅商品场景中与订阅ID一一对应。
+ */
+ private String purchaseToken;
+
+ /**
+ * 订阅状态。
+ * • 1:生效状态
+ * • 2:已到期
+ * • 3:尝试扣费
+ * • 5:撤销
+ * • 6:暂停
+ */
+ private Integer status;
+
+ /**
+ * 自动续期订阅商品的过期时间,UTC时间戳,以毫秒为单位。
+ */
+ private Long expiresTime;
+
+ /**
+ * 当前订阅最新的一笔购买订单。包含的参数请参见PurchaseOrderPayload。
+ */
+ private PurchaseOrderPayload lastPurchaseOrder;
+
+ /**
+ * 当前订阅最新的购买订单列表,包含续期、延期、折算等产生的购买订单。
+ * 购买订单包含的参数请参见PurchaseOrderPayload。
+ */
+ private List recentPurchaseOrderList;
+
+ /**
+ * 当前订阅最新的未来扣费计划,包含的参数请参见SubRenewalInfo。
+ */
+ private SubRenewalInfo renewalInfo;
+
+
+}
diff --git a/sf-payment/src/main/java/com/sf/payment/service/impl/HuaweiPaymentServiceImpl.java b/sf-payment/src/main/java/com/sf/payment/service/impl/HuaweiPaymentServiceImpl.java
index 2cf3347..1a86679 100644
--- a/sf-payment/src/main/java/com/sf/payment/service/impl/HuaweiPaymentServiceImpl.java
+++ b/sf-payment/src/main/java/com/sf/payment/service/impl/HuaweiPaymentServiceImpl.java
@@ -6,26 +6,32 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.JSONObject;
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.interfaces.DecodedJWT;
import com.sf.common.utils.SecurityUtils;
+import com.sf.common.utils.SnowflakeIdWorker;
import com.sf.order.domain.OrderInfo;
import com.sf.order.service.IOrderInfoService;
import com.sf.payment.config.HuaweiPaymentConfig;
-import com.sf.payment.domain.HuaweiPurchasesVerifyDTO;
-import com.sf.payment.domain.HuaweiPurchasesVerifyResponseDTO;
-import com.sf.payment.domain.InAppPurchaseData;
+import com.sf.payment.constant.GoodsConstants;
+import com.sf.payment.domain.*;
import com.sf.payment.service.IHuaweiPaymentService;
+import com.sf.payment.utils.HuaweiTokenGenerator;
+import com.sf.service.domain.GoodsMessages;
+import com.sf.service.service.IGoodsMessagesService;
import com.sf.system.domain.UserMember;
import com.sf.system.service.IUserMemberService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
+import org.springframework.util.Base64Utils;
+import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
+import java.security.MessageDigest;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.X509EncodedKeySpec;
@@ -45,58 +51,204 @@ import java.util.Map;
@Service
public class HuaweiPaymentServiceImpl implements IHuaweiPaymentService {
- // token url to get the authorization
+ /**
+ * token url to get the authorization
+ */
private static final String TOKEN_URL = "https://oauth-login.cloud.huawei.com/oauth2/v3/token";
- private static final String VERIFY_TOKEN_URL = "https://orders-drcn.iap.cloud.huawei.com.cn/applications/purchases/tokens/verify";
+
+ /**
+ * 查询消耗型/非消耗型商品的订单最新状态。
+ */
+ private static final String ORDER_STATUS_QUERY_URL = "/order/harmony/v1/application/order/status/query";
+
+ /**
+ * 查询自动续期订阅商品的最新状态。
+ */
+ private static final String SUBSCRIPTION_STATUS_QUERY_URL = "/subscription/harmony/v1/application/subscription/status/query";
+
+ /**
+ * 站点信息。(中国)
+ */
+ private static final String ROOT_URL = "https://iap.cloud.huawei.com";
private static final String PUBLIC_KEY = "PUBLIC_KEY";
- @Autowired
+ @Resource
private IOrderInfoService orderInfoService;
- @Autowired
+ @Resource
private IUserMemberService userMemberService;
- @Autowired
+ @Resource
+ private IGoodsMessagesService goodsMessagesService;
+
+ @Resource
private HuaweiPaymentConfig huaweiPaymentConfig;
+ @Resource
+ private SnowflakeIdWorker snowflakeIdWorker;
+
+
@Override
@Transactional(rollbackFor = Exception.class)
public void purchasesVerify(HuaweiPurchasesVerifyDTO verifyDTO) {
- // construct the Authorization in Header
- Map headers = buildAuthorization(getAppAT(huaweiPaymentConfig.getClientId(), huaweiPaymentConfig.getClientSecret()));
+ // 待发放会员商品
+ PurchaseOrderPayload huaweiQueryResponsePurchaseOrderPayload;
+ // 验证 TODO 证书验签官网未实现
+ if (GoodsConstants.GOODS_TYPE_CONSUMABLE.equals(verifyDTO.getType())
+ || GoodsConstants.GOODS_TYPE_NON_CONSUMABLE.equals(verifyDTO.getType())) {
+ Assert.hasText(verifyDTO.getJwsPurchaseOrder(), "订单信息不能为空");
+ // 消耗/非消耗商品购买验证
+ consumablePurchasesVerify(verifyDTO.getJwsPurchaseOrder());
+ } else if (GoodsConstants.GOODS_TYPE_AUTOMATIC_RENEWAL_SUBSCRIPTION.equals(verifyDTO.getType())) {
+ Assert.hasText(verifyDTO.getJwsSubscriptionStatus(), "订单信息不能为空");
+ // 订阅商品购买验证
+ subscriptionPurchasesVerify(verifyDTO.getJwsSubscriptionStatus());
+ } else {
+ throw new IllegalArgumentException("商品类型错误!");
+ }
+ }
+ private PurchaseOrderPayload subscriptionPurchasesVerify(String jwsSubscriptionStatus) {
+ DecodedJWT decodedJWT = JWT.decode(jwsSubscriptionStatus);
+ //String header = decodedJWT.getHeader();
+ String payload = decodedJWT.getPayload();
+ // 前面应该不是base64编码后的,官网说都是编码后的,但是解码会报错
+ //String signature = decodedJWT.getSignature();
+ String decodeAppPayload = new String(Base64Utils.decode(payload.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
+ // String decodeHeader = new String(Base64Utils.decode(header.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
+ // String decodeSignature = new String(Base64Utils.decode(signature.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
+ SubGroupStatusPayload appSubGroupStatusPayload = JSON.parseObject(decodeAppPayload, SubGroupStatusPayload.class);
+ SubscriptionStatus lastSubscriptionStatus = appSubGroupStatusPayload.getLastSubscriptionStatus();
+ PurchaseOrderPayload lastPurchaseOrder = lastSubscriptionStatus.getLastPurchaseOrder();
// pack the request body
Map bodyMap = new HashMap<>();
- bodyMap.put("purchaseToken", verifyDTO.getPurchaseToken());
- bodyMap.put("productId", verifyDTO.getProductId());
+ bodyMap.put("purchaseToken", lastPurchaseOrder.getPurchaseToken());
+ bodyMap.put("purchaseOrderId", lastPurchaseOrder.getPurchaseOrderId());
+ // construct the Authorization in Header
+ Map headers = buildAuthorization(huaweiPaymentConfig.getAppId(), bodyMap);
- String response = HttpUtil.createPost(VERIFY_TOKEN_URL)
+ // 订阅状态查询
+ String response = HttpUtil.createPost(ROOT_URL + SUBSCRIPTION_STATUS_QUERY_URL)
.addHeaders(headers)
.body(JSON.toJSONString(bodyMap))
.execute().body();
- HuaweiPurchasesVerifyResponseDTO huaweiPurchasesVerifyResponseDTO = JSON.parseObject(response, HuaweiPurchasesVerifyResponseDTO.class);
- InAppPurchaseData inAppPurchaseData = JSON.parseObject(huaweiPurchasesVerifyResponseDTO.getPurchaseTokenData(), InAppPurchaseData.class);
- // 获取服务订单
- OrderInfo orderInfo = orderInfoService.selectOrderInfoByOrderNo(verifyDTO.getOrderNo());
- // 校验订单
- boolean checkSuccessOrder = checkSuccessOrder(huaweiPurchasesVerifyResponseDTO.getPurchaseTokenData()
- , huaweiPurchasesVerifyResponseDTO.getDataSignature()
- , PUBLIC_KEY
- , huaweiPurchasesVerifyResponseDTO.getSignatureAlgorithm()
- , orderInfo);
+ log.info("订单状态查询返回信息:{}", response);
+ HuaweiQueryResponse huaweiQueryResponse = JSON.parseObject(response, HuaweiQueryResponse.class);
+ if (!"0".equals(huaweiQueryResponse.getResponseCode())) {
+ throw new RuntimeException("订单状态查询失败");
+ }
+ DecodedJWT huaweiQueryResponseDecodedJWT = JWT.decode(huaweiQueryResponse.getJwsSubGroupStatus());
+ String huaweiQueryResponsepayload = huaweiQueryResponseDecodedJWT.getPayload();
+ String decodeHuaweiQueryResponsepayload = new String(Base64Utils.decode(huaweiQueryResponsepayload.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
+ SubGroupStatusPayload subGroupStatusPayload = JSON.parseObject(decodeHuaweiQueryResponsepayload, SubGroupStatusPayload.class);
+ PurchaseOrderPayload huaweiQueryResponsePurchaseOrderPayload = subGroupStatusPayload.getLastSubscriptionStatus().getLastPurchaseOrder();
+ // 发货
+ return delivery(lastPurchaseOrder, huaweiQueryResponsePurchaseOrderPayload);
+ }
- Assert.isTrue(checkSuccessOrder, "订单校验失败,请重试");
- Assert.isTrue(inAppPurchaseData.getPurchaseState()==0, "订单未完成购买");
- DateTime payTime = DateUtil.date(inAppPurchaseData.getPurchaseTime());
- UserMember userMember = userMemberService.selectUserMemberByUserId(orderInfo.getCreateUserId());
+ /**
+ * 发货
+ * @param purchaseOrder
+ * @param huaweiQueryResponsePurchaseOrderPayload
+ * @return
+ */
+ private PurchaseOrderPayload delivery(PurchaseOrderPayload purchaseOrder, PurchaseOrderPayload huaweiQueryResponsePurchaseOrderPayload) {
+ Assert.isTrue(purchaseOrder.getPurchaseOrderId().equals(huaweiQueryResponsePurchaseOrderPayload.getPurchaseOrderId()), "订单不一致,发货失败!");
+ if (2 == huaweiQueryResponsePurchaseOrderPayload.getFinishStatus()) {
+ // 还未发货
+ // 查询平台是否配置该商品
+ // 查询平台是否配置该商品
+ GoodsMessages goods = goodsMessagesService.selectGoodsMessagesByCode(huaweiQueryResponsePurchaseOrderPayload.getProductId());
+ Assert.notNull(goods, "未配置此商品,请检查商品配置");
+ Assert.isTrue(goods.getOriginalPrice().equals(huaweiQueryResponsePurchaseOrderPayload.getPrice()), "商品价格与订单价格不一致,请检查价格配置");
+ // 创建完成订单
+ createOrder(huaweiQueryResponsePurchaseOrderPayload, goods);
+ // 发放会员权益
+ distributeMembershipBenefits(huaweiQueryResponsePurchaseOrderPayload);
+ } else {
+ log.info("华为应用内支付订单已发货!{}", JSON.toJSONString(huaweiQueryResponsePurchaseOrderPayload));
+ }
+ return huaweiQueryResponsePurchaseOrderPayload;
+ }
+
+ private PurchaseOrderPayload consumablePurchasesVerify(String jwsPurchaseOrder) {
+ DecodedJWT decodedJWT = JWT.decode(jwsPurchaseOrder);
+ //String header = decodedJWT.getHeader();
+ String payload = decodedJWT.getPayload();
+ // 前面应该不是base64编码后的,官网说都是编码后的,但是解码会报错
+ //String signature = decodedJWT.getSignature();
+ String decodeAppPayload = new String(Base64Utils.decode(payload.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
+ // String decodeHeader = new String(Base64Utils.decode(header.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
+ // String decodeSignature = new String(Base64Utils.decode(signature.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
+ PurchaseOrderPayload appPurchaseOrderPayload = JSON.parseObject(decodeAppPayload, PurchaseOrderPayload.class);
+ // pack the request body
+ Map bodyMap = new HashMap<>();
+ bodyMap.put("purchaseToken", appPurchaseOrderPayload.getPurchaseToken());
+ bodyMap.put("purchaseOrderId", appPurchaseOrderPayload.getPurchaseOrderId());
+ // construct the Authorization in Header
+ Map headers = buildAuthorization(huaweiPaymentConfig.getAppId(), bodyMap);
+
+ // 订单状态查询
+ String response = HttpUtil.createPost(ROOT_URL + ORDER_STATUS_QUERY_URL)
+ .addHeaders(headers)
+ .body(JSON.toJSONString(bodyMap))
+ .execute().body();
+ log.info("订单状态查询返回信息:{}", response);
+ HuaweiQueryResponse huaweiQueryResponse = JSON.parseObject(response, HuaweiQueryResponse.class);
+ if (!"0".equals(huaweiQueryResponse.getResponseCode())) {
+ throw new RuntimeException("订单状态查询失败");
+ }
+ DecodedJWT huaweiQueryResponseDecodedJWT = JWT.decode(huaweiQueryResponse.getJwsPurchaseOrder());
+ // String huaweiQueryResponseHeader = huaweiQueryResponseDecodedJWT.getHeader();
+ String huaweiQueryResponsepayload = huaweiQueryResponseDecodedJWT.getPayload();
+ // String huaweiQueryResponsesignature = huaweiQueryResponseDecodedJWT.getSignature();
+
+ //String decodehuaweiQueryResponseHeader = new String(Base64Utils.decode(huaweiQueryResponseHeader.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
+ String decodehuaweiQueryResponsepayload = new String(Base64Utils.decode(huaweiQueryResponsepayload.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
+ // String decodehuaweiQueryResponsesignature = new String(Base64Utils.decode(huaweiQueryResponsesignature.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
+
+ PurchaseOrderPayload huaweiQueryResponsePurchaseOrderPayload = JSON.parseObject(decodehuaweiQueryResponsepayload, PurchaseOrderPayload.class);
+ // 暂时只做简单验证
+ return delivery(appPurchaseOrderPayload, huaweiQueryResponsePurchaseOrderPayload);
+ }
+
+ private void createOrder(PurchaseOrderPayload appPurchaseOrderPayload, GoodsMessages goods) {
+ Long userId = SecurityUtils.getUserId();
+ OrderInfo orderInfo = new OrderInfo();
+ orderInfo.setOrderNo(snowflakeIdWorker.nextId());
+ orderInfo.setOrderStatus(6L);
+ orderInfo.setPayType(1L);
+ orderInfo.setPayChannel(2L);
+ orderInfo.setOrderAmt(appPurchaseOrderPayload.getPrice());
+ orderInfo.setPayAmt(appPurchaseOrderPayload.getPrice());
+ orderInfo.setReallyAmt(appPurchaseOrderPayload.getPrice());
+ orderInfo.setReceiveType(0L);
+ orderInfo.setGoodsId(goods.getId());
+ orderInfo.setPayTime(DateUtil.date(appPurchaseOrderPayload.getPurchaseTime()));
+ orderInfo.setCreateUserId(userId);
+ orderInfo.setUpdateUserId(userId);
+ orderInfo.setOutOrderNo(appPurchaseOrderPayload.getPurchaseOrderId());
+ orderInfo.setPayData(JSON.toJSONString(appPurchaseOrderPayload));
+ orderInfo.setGoodsPrice(goods.getOriginalPrice());
+ orderInfo.setGoodsType(goods.getGoodsType());
+ orderInfo.setGoodsCode(goods.getGoodsCode());
+ orderInfoService.insertOrder(orderInfo);
+
+ }
+
+ private void distributeMembershipBenefits(PurchaseOrderPayload purchaseOrderPayload) {
+ // 发放会员权益
+ Long userId = SecurityUtils.getUserId();
+ UserMember userMember = userMemberService.selectUserMemberByUserId(userId);
if (userMember == null) {
// 添加会员信息
- boolean isSubscription = verifyDTO.getKind() == 2;
+ boolean isSubscription = GoodsConstants.GOODS_TYPE_AUTOMATIC_RENEWAL_SUBSCRIPTION.equals(purchaseOrderPayload.getProductType());
+ DateTime payTime = DateUtil.date(purchaseOrderPayload.getPurchaseTime());
userMember = new UserMember();
userMember.setMemberLevel(isSubscription ? 1 : 2);
userMember.setSubscriptionStatus(isSubscription ? 1 : 0);
- userMember.setUserId(orderInfo.getCreateUserId());
+ userMember.setUserId(userId);
userMember.setIntegration(0L);
DateTime expirationTime = DateUtil.offset(payTime, DateField.MONTH, 1);
userMember.setExpirationTime(expirationTime);
@@ -110,48 +262,56 @@ public class HuaweiPaymentServiceImpl implements IHuaweiPaymentService {
userMember.setUpdateTime(new Date());
userMemberService.updateUserMember(userMember);
}
- // 更新订单状态
- orderInfo.setPayTime(payTime);
- orderInfo.setOrderStatus(3L);
- orderInfo.setPayChannel(2L);
- orderInfo.setPayAmt(orderInfo.getOrderAmt());
- orderInfo.setReallyAmt(orderInfo.getOrderAmt());
- orderInfo.setOrderStatus(3L);
- orderInfo.setPayData(huaweiPurchasesVerifyResponseDTO.getPurchaseTokenData());
- orderInfoService.updateOrderInfo(orderInfo);
}
- /**
- * Gets App Level AccessToken.
- */
- public static String getAppAT(String clientId, String clientSecret) {
- // fetch accessToken
- Map form = new HashMap<>(8);
- form.put("grant_type", "client_credentials");
- form.put("client_secret", clientSecret);
- form.put("client_id", clientId);
- String atResponse = HttpUtil.post(TOKEN_URL, form);
- log.info("getAppAT Response : {}", atResponse);
- JSONObject parseObject = JSON.parseObject(atResponse);
- return parseObject.getString("access_token");
- }
/**
* Build Authorization in Header
*
- * @param appAt appAt
* @return headers
*/
- public static Map buildAuthorization(String appAt) {
- String oriString = MessageFormat.format("APPAT:{0}", appAt);
- String authorization =
- MessageFormat.format("Basic {0}", Base64.encodeBase64String(oriString.getBytes(StandardCharsets.UTF_8)));
+ public static Map buildAuthorization(String appId, Map body) {
+ Map jwtHeader = new HashMap<>(8);
+ jwtHeader.put("alg", "ES256");
+ jwtHeader.put("typ", "JWT");
+ jwtHeader.put("kid", "0ae3e1be-374b-43a5-a297-045addbf76eb");
+ Map jwtPayload = new HashMap<>(8);
+ jwtPayload.put("iss", "f59509e6-dd17-4644-b832-ff05233146c8");
+ jwtPayload.put("aud", "iap-v1");
+ jwtPayload.put("iat", DateUtil.currentSeconds());
+ jwtPayload.put("exp", DateUtil.currentSeconds() + 1800L); // 半小时过期
+ jwtPayload.put("aid", appId);
+ jwtPayload.put("digest", getJwtPayloadDigest(body));
+
+ String token = HuaweiTokenGenerator.createToken(jwtHeader, jwtPayload);
+ // String authorization = MessageFormat.format("Basic {0}", Base64.encodeBase64String(oriString.getBytes(StandardCharsets.UTF_8)));
+ String authorization = MessageFormat.format("Bearer {0}", token);
Map headers = new HashMap<>();
headers.put("Authorization", authorization);
headers.put("Content-Type", "application/json; charset=UTF-8");
return headers;
}
+ private static String getJwtPayloadDigest(Map body) {
+ try {
+ MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
+ messageDigest.update(JSON.toJSONString(body).getBytes(StandardCharsets.UTF_8));
+ byte[] digestByte = messageDigest.digest();
+ StringBuilder stringBuffer = new StringBuilder();
+ String temp;
+ for (byte aByte : digestByte) {
+ temp = Integer.toHexString(aByte & 0xFF);
+ if (temp.length() == 1) {
+ stringBuffer.append("0");
+ }
+ stringBuffer.append(temp);
+ }
+ return stringBuffer.toString();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
/**
* 校验签名信息,校验InAppPurchaseData中的productId、price、currency等信息的一致性
*
@@ -173,15 +333,15 @@ public class HuaweiPaymentServiceImpl implements IHuaweiPaymentService {
/**
* 校验InAppPurchaseData中的productId、price、currency等信息的一致性
*
- * @param content 结果字符串
- * @param yourOrderInfo 您的订单信息,包括productId、price、currency
+ * @param content 结果字符串
+ * @param orderInfo 您的订单信息,包括productId、price、currency
* @return 是否校验通过
*/
- public static boolean checkProductIdAndPriceAndCurrency(String content, OrderInfo yourOrderInfo) {
+ public static boolean checkProductIdAndPriceAndCurrency(String content, OrderInfo orderInfo) {
InAppPurchaseData inAppPurchaseData = JSON.parseObject(content, InAppPurchaseData.class);
// 校验InAppPurchaseData中的productId、price、currency等信息的一致性
- return inAppPurchaseData.getProductId().equals(yourOrderInfo.getGoodsId())
- && inAppPurchaseData.getPrice().equals(yourOrderInfo.getOrderAmt());
+ return inAppPurchaseData.getProductId().equals(orderInfo.getGoodsId())
+ && inAppPurchaseData.getPrice().equals(orderInfo.getOrderAmt());
}
/**
diff --git a/sf-payment/src/main/java/com/sf/payment/utils/HuaweiTokenGenerator.java b/sf-payment/src/main/java/com/sf/payment/utils/HuaweiTokenGenerator.java
new file mode 100644
index 0000000..4572ea6
--- /dev/null
+++ b/sf-payment/src/main/java/com/sf/payment/utils/HuaweiTokenGenerator.java
@@ -0,0 +1,43 @@
+package com.sf.payment.utils;
+import cn.hutool.core.io.resource.ClassPathResource;
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+import org.apache.commons.io.IOUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Base64;
+
+import java.util.Map;
+
+public class HuaweiTokenGenerator {
+
+ public static String createToken(Map jwtHeader, Map jwtPayload) {
+ try {
+ // AppGallery Connect 华为应用内支付配置密钥,下载私钥文件
+ ClassPathResource classPathResource = new ClassPathResource("IAPKey_0ae3e1be-374b-43a5-a297-045addbf76eb.p8");
+ InputStream IAPKeyStream = classPathResource.getStream();
+ String content = IOUtils.toString(IAPKeyStream, String.valueOf(StandardCharsets.UTF_8));
+ String privateKey = content
+ .replace("-----BEGIN PRIVATE KEY-----", "")
+ .replaceAll("\\R+", "")
+ .replace("-----END PRIVATE KEY-----", "");
+ KeyFactory keyFactory = KeyFactory.getInstance("EC");
+ byte[] privateKeyBytes = Base64.getDecoder().decode(privateKey);
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
+ ECPrivateKey ecPrivateKey = (ECPrivateKey) keyFactory.generatePrivate(keySpec);
+ return JWT.create()
+ .withHeader(jwtHeader)
+ .withPayload(jwtPayload)
+ .sign(Algorithm.ECDSA256(ecPrivateKey));
+ } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/sf-payment/src/main/resources/IAPKey_0ae3e1be-374b-43a5-a297-045addbf76eb.p8 b/sf-payment/src/main/resources/IAPKey_0ae3e1be-374b-43a5-a297-045addbf76eb.p8
new file mode 100644
index 0000000..e1ebbeb
--- /dev/null
+++ b/sf-payment/src/main/resources/IAPKey_0ae3e1be-374b-43a5-a297-045addbf76eb.p8
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQggG04243qynU/yWYy
+XpYVy9ZWMuLKzZiwhXCBWQBCOLigCgYIKoZIzj0DAQehRANCAARNln2/d+TM2pIO
+LWQzvI77gPAVEvVCSlIuiJ+J7CJSG5KCysBaEeiiD5cc4dZWnUBijF8FBh7nDLaH
+VwFXfrS+
+-----END PRIVATE KEY-----
diff --git a/sf-service/pom.xml b/sf-service/pom.xml
new file mode 100644
index 0000000..84ffb42
--- /dev/null
+++ b/sf-service/pom.xml
@@ -0,0 +1,33 @@
+
+
+
+ smarterFramework
+ com.smarterFramework
+ 1.0.0
+
+ 4.0.0
+
+ sf-service
+
+
+ 业务模块
+
+
+
+
+
+
+ com.smarterFramework
+ sf-common
+
+
+ com.smarterFramework
+ sf-framework
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sf-admin/src/main/java/com/sf/goods/controller/GoodsMessagesController.java b/sf-service/src/main/java/com/sf/service/controller/GoodsMessagesController.java
similarity index 83%
rename from sf-admin/src/main/java/com/sf/goods/controller/GoodsMessagesController.java
rename to sf-service/src/main/java/com/sf/service/controller/GoodsMessagesController.java
index cd2ca0a..4117dab 100644
--- a/sf-admin/src/main/java/com/sf/goods/controller/GoodsMessagesController.java
+++ b/sf-service/src/main/java/com/sf/service/controller/GoodsMessagesController.java
@@ -1,7 +1,10 @@
-package com.sf.goods.controller;
+package com.sf.service.controller;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
+
+import com.sf.service.domain.GoodsMessages;
+import com.sf.service.service.IGoodsMessagesService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
@@ -16,19 +19,17 @@ import com.sf.common.annotation.Log;
import com.sf.common.core.controller.BaseController;
import com.sf.common.core.domain.AjaxResult;
import com.sf.common.enums.BusinessType;
-import com.sf.goods.domain.GoodsMessages;
-import com.sf.goods.service.IGoodsMessagesService;
import com.sf.common.utils.poi.ExcelUtil;
import com.sf.common.core.page.TableDataInfo;
/**
* 商品信息Controller
- *
- * @author ztzh
- * @date 2024-04-11
+ *
+ * @author zoukun
+ * @date 2024-04-18
*/
@RestController
-@RequestMapping("/goods/goods")
+@RequestMapping("/service/goods")
public class GoodsMessagesController extends BaseController
{
@Autowired
@@ -37,7 +38,7 @@ public class GoodsMessagesController extends BaseController
/**
* 查询商品信息列表
*/
- @PreAuthorize("@ss.hasPermi('goods:goods:list')")
+ @PreAuthorize("@ss.hasPermi('service:goods:list')")
@GetMapping("/list")
public TableDataInfo list(GoodsMessages goodsMessages)
{
@@ -49,7 +50,7 @@ public class GoodsMessagesController extends BaseController
/**
* 导出商品信息列表
*/
- @PreAuthorize("@ss.hasPermi('goods:goods:export')")
+ @PreAuthorize("@ss.hasPermi('service:goods:export')")
@Log(title = "商品信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, GoodsMessages goodsMessages)
@@ -62,7 +63,7 @@ public class GoodsMessagesController extends BaseController
/**
* 获取商品信息详细信息
*/
- @PreAuthorize("@ss.hasPermi('goods:goods:query')")
+ @PreAuthorize("@ss.hasPermi('service:goods:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
@@ -72,7 +73,7 @@ public class GoodsMessagesController extends BaseController
/**
* 新增商品信息
*/
- @PreAuthorize("@ss.hasPermi('goods:goods:add')")
+ @PreAuthorize("@ss.hasPermi('service:goods:add')")
@Log(title = "商品信息", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody GoodsMessages goodsMessages)
@@ -83,7 +84,7 @@ public class GoodsMessagesController extends BaseController
/**
* 修改商品信息
*/
- @PreAuthorize("@ss.hasPermi('goods:goods:edit')")
+ @PreAuthorize("@ss.hasPermi('service:goods:edit')")
@Log(title = "商品信息", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody GoodsMessages goodsMessages)
@@ -94,9 +95,9 @@ public class GoodsMessagesController extends BaseController
/**
* 删除商品信息
*/
- @PreAuthorize("@ss.hasPermi('goods:goods:remove')")
+ @PreAuthorize("@ss.hasPermi('service:goods:remove')")
@Log(title = "商品信息", businessType = BusinessType.DELETE)
- @DeleteMapping("/{ids}")
+ @DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(goodsMessagesService.deleteGoodsMessagesByIds(ids));
diff --git a/sf-admin/src/main/java/com/sf/goods/domain/GoodsMessages.java b/sf-service/src/main/java/com/sf/service/domain/GoodsMessages.java
similarity index 79%
rename from sf-admin/src/main/java/com/sf/goods/domain/GoodsMessages.java
rename to sf-service/src/main/java/com/sf/service/domain/GoodsMessages.java
index 16a24a5..86c36bb 100644
--- a/sf-admin/src/main/java/com/sf/goods/domain/GoodsMessages.java
+++ b/sf-service/src/main/java/com/sf/service/domain/GoodsMessages.java
@@ -1,4 +1,4 @@
-package com.sf.goods.domain;
+package com.sf.service.domain;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@@ -8,8 +8,8 @@ import com.sf.common.core.domain.BaseEntity;
/**
* 商品信息对象 GOODS_MESSAGES
*
- * @author ztzh
- * @date 2024-04-11
+ * @author zoukun
+ * @date 2024-04-18
*/
public class GoodsMessages extends BaseEntity
{
@@ -26,6 +26,7 @@ public class GoodsMessages extends BaseEntity
private Long stockId;
/** 审核状态,1通过,0未通过 */
+ @Excel(name = "审核状态,1通过,0未通过")
private Long reviewStatus;
/** 商品标题 */
@@ -36,16 +37,23 @@ public class GoodsMessages extends BaseEntity
@Excel(name = "商品图片")
private String productPicture;
- /** 原价格 */
- @Excel(name = "原价格")
+ /** 商品原价 */
+ @Excel(name = "商品原价")
private Long originalPrice;
/** 商品描述 */
@Excel(name = "商品描述")
private String productDesc;
+ /** 商品类型。 * • 0:消耗型商品 * • 1:非消耗型商品 * • 2:自动续期订阅商品 */
+ @Excel(name = "商品类型。 * • 0:消耗型商品 * • 1:非消耗型商品 * • 2:自动续期订阅商品")
+ private Integer goodsType;
+
+ /** 商品规格 */
+ @Excel(name = "商品规格")
+ private String goodsSpec;
+
/** 排序 */
- @Excel(name = "排序")
private Long orderNum;
/** 逻辑删除,0:未删除,1:删除 */
@@ -57,13 +65,12 @@ public class GoodsMessages extends BaseEntity
/** 更新人 */
private String modified;
- /** 商品类型 */
- @Excel(name = "商品类型")
- private String goodsType;
+ /** 商品名称 */
+ private String goodsName;
- /** 商品规格 */
- @Excel(name = "商品规格")
- private String goodsSpec;
+ /** 商品型号 */
+ @Excel(name = "商品型号")
+ private String goodsModel;
public void setId(Long id)
{
@@ -137,6 +144,24 @@ public class GoodsMessages extends BaseEntity
{
return productDesc;
}
+ public void setGoodsType(Integer goodsType)
+ {
+ this.goodsType = goodsType;
+ }
+
+ public Integer getGoodsType()
+ {
+ return goodsType;
+ }
+ public void setGoodsSpec(String goodsSpec)
+ {
+ this.goodsSpec = goodsSpec;
+ }
+
+ public String getGoodsSpec()
+ {
+ return goodsSpec;
+ }
public void setOrderNum(Long orderNum)
{
this.orderNum = orderNum;
@@ -173,23 +198,23 @@ public class GoodsMessages extends BaseEntity
{
return modified;
}
- public void setGoodsType(String goodsType)
+ public void setGoodsName(String goodsName)
{
- this.goodsType = goodsType;
+ this.goodsName = goodsName;
}
- public String getGoodsType()
+ public String getGoodsName()
{
- return goodsType;
+ return goodsName;
}
- public void setGoodsSpec(String goodsSpec)
+ public void setGoodsModel(String goodsModel)
{
- this.goodsSpec = goodsSpec;
+ this.goodsModel = goodsModel;
}
- public String getGoodsSpec()
+ public String getGoodsModel()
{
- return goodsSpec;
+ return goodsModel;
}
@Override
@@ -203,14 +228,16 @@ public class GoodsMessages extends BaseEntity
.append("productPicture", getProductPicture())
.append("originalPrice", getOriginalPrice())
.append("productDesc", getProductDesc())
+ .append("goodsType", getGoodsType())
+ .append("goodsSpec", getGoodsSpec())
.append("orderNum", getOrderNum())
.append("isDelete", getIsDelete())
.append("created", getCreated())
.append("modified", getModified())
.append("createTime", getCreateTime())
.append("updateTime", getUpdateTime())
- .append("goodsType", getGoodsType())
- .append("goodsSpec", getGoodsSpec())
+ .append("goodsName", getGoodsName())
+ .append("goodsModel", getGoodsModel())
.toString();
}
}
diff --git a/sf-admin/src/main/java/com/sf/goods/mapper/GoodsMessagesMapper.java b/sf-service/src/main/java/com/sf/service/mapper/GoodsMessagesMapper.java
similarity index 87%
rename from sf-admin/src/main/java/com/sf/goods/mapper/GoodsMessagesMapper.java
rename to sf-service/src/main/java/com/sf/service/mapper/GoodsMessagesMapper.java
index dfb2188..02a2f1a 100644
--- a/sf-admin/src/main/java/com/sf/goods/mapper/GoodsMessagesMapper.java
+++ b/sf-service/src/main/java/com/sf/service/mapper/GoodsMessagesMapper.java
@@ -1,13 +1,13 @@
-package com.sf.goods.mapper;
+package com.sf.service.mapper;
import java.util.List;
-import com.sf.goods.domain.GoodsMessages;
+import com.sf.service.domain.GoodsMessages;
/**
* 商品信息Mapper接口
*
- * @author ztzh
- * @date 2024-04-11
+ * @author zoukun
+ * @date 2024-04-18
*/
public interface GoodsMessagesMapper
{
@@ -58,4 +58,6 @@ public interface GoodsMessagesMapper
* @return 结果
*/
public int deleteGoodsMessagesByIds(Long[] ids);
+
+ GoodsMessages selectGoodsMessagesByCode(String goodsCode);
}
diff --git a/sf-admin/src/main/java/com/sf/goods/service/IGoodsMessagesService.java b/sf-service/src/main/java/com/sf/service/service/IGoodsMessagesService.java
similarity index 87%
rename from sf-admin/src/main/java/com/sf/goods/service/IGoodsMessagesService.java
rename to sf-service/src/main/java/com/sf/service/service/IGoodsMessagesService.java
index 3f1c08a..29f7dab 100644
--- a/sf-admin/src/main/java/com/sf/goods/service/IGoodsMessagesService.java
+++ b/sf-service/src/main/java/com/sf/service/service/IGoodsMessagesService.java
@@ -1,13 +1,13 @@
-package com.sf.goods.service;
+package com.sf.service.service;
import java.util.List;
-import com.sf.goods.domain.GoodsMessages;
+import com.sf.service.domain.GoodsMessages;
/**
* 商品信息Service接口
*
- * @author ztzh
- * @date 2024-04-11
+ * @author zoukun
+ * @date 2024-04-18
*/
public interface IGoodsMessagesService
{
@@ -58,4 +58,6 @@ public interface IGoodsMessagesService
* @return 结果
*/
public int deleteGoodsMessagesById(Long id);
+
+ GoodsMessages selectGoodsMessagesByCode(String goodsCode);
}
diff --git a/sf-admin/src/main/java/com/sf/goods/service/impl/GoodsMessagesServiceImpl.java b/sf-service/src/main/java/com/sf/service/service/impl/GoodsMessagesServiceImpl.java
similarity index 80%
rename from sf-admin/src/main/java/com/sf/goods/service/impl/GoodsMessagesServiceImpl.java
rename to sf-service/src/main/java/com/sf/service/service/impl/GoodsMessagesServiceImpl.java
index 45b7b42..0541ba8 100644
--- a/sf-admin/src/main/java/com/sf/goods/service/impl/GoodsMessagesServiceImpl.java
+++ b/sf-service/src/main/java/com/sf/service/service/impl/GoodsMessagesServiceImpl.java
@@ -1,18 +1,19 @@
-package com.sf.goods.service.impl;
+package com.sf.service.service.impl;
import java.util.List;
import com.sf.common.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-import com.sf.goods.mapper.GoodsMessagesMapper;
-import com.sf.goods.domain.GoodsMessages;
-import com.sf.goods.service.IGoodsMessagesService;
+import com.sf.service.mapper.GoodsMessagesMapper;
+import com.sf.service.domain.GoodsMessages;
+import com.sf.service.service.IGoodsMessagesService;
+import org.springframework.util.StringUtils;
/**
* 商品信息Service业务层处理
*
- * @author ztzh
- * @date 2024-04-11
+ * @author zoukun
+ * @date 2024-04-18
*/
@Service
public class GoodsMessagesServiceImpl implements IGoodsMessagesService
@@ -93,4 +94,12 @@ public class GoodsMessagesServiceImpl implements IGoodsMessagesService
{
return goodsMessagesMapper.deleteGoodsMessagesById(id);
}
+
+ @Override
+ public GoodsMessages selectGoodsMessagesByCode(String goodsCode) {
+ if (StringUtils.hasText(goodsCode)){
+ return goodsMessagesMapper.selectGoodsMessagesByCode(goodsCode);
+ }
+ return null;
+ }
}
diff --git a/sf-admin/src/main/resources/mapper/goods/GoodsMessagesMapper.xml b/sf-service/src/main/resources/mapper/service/GoodsMessagesMapper.xml
similarity index 76%
rename from sf-admin/src/main/resources/mapper/goods/GoodsMessagesMapper.xml
rename to sf-service/src/main/resources/mapper/service/GoodsMessagesMapper.xml
index ffa20fa..3e55f20 100644
--- a/sf-admin/src/main/resources/mapper/goods/GoodsMessagesMapper.xml
+++ b/sf-service/src/main/resources/mapper/service/GoodsMessagesMapper.xml
@@ -1,118 +1,130 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- select id, goods_code, stock_id, review_status, product_title, product_picture, original_price, product_desc, order_num, is_delete, created, modified, create_time, update_time, goods_type, goods_spec from GOODS_MESSAGES
-
-
-
-
-
-
-
-
- insert into GOODS_MESSAGES
-
- goods_code,
- stock_id,
- review_status,
- product_title,
- product_picture,
- original_price,
- product_desc,
- order_num,
- is_delete,
- created,
- modified,
- create_time,
- update_time,
- goods_type,
- goods_spec,
-
-
- #{goodsCode},
- #{stockId},
- #{reviewStatus},
- #{productTitle},
- #{productPicture},
- #{originalPrice},
- #{productDesc},
- #{orderNum},
- #{isDelete},
- #{created},
- #{modified},
- #{createTime},
- #{updateTime},
- #{goodsType},
- #{goodsSpec},
-
-
-
-
- update GOODS_MESSAGES
-
- goods_code = #{goodsCode},
- stock_id = #{stockId},
- review_status = #{reviewStatus},
- product_title = #{productTitle},
- product_picture = #{productPicture},
- original_price = #{originalPrice},
- product_desc = #{productDesc},
- order_num = #{orderNum},
- is_delete = #{isDelete},
- created = #{created},
- modified = #{modified},
- create_time = #{createTime},
- update_time = #{updateTime},
- goods_type = #{goodsType},
- goods_spec = #{goodsSpec},
-
- where id = #{id}
-
-
-
- delete from GOODS_MESSAGES where id = #{id}
-
-
-
- delete from GOODS_MESSAGES where id in
-
- #{id}
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select id, goods_code, stock_id, review_status, product_title, product_picture, original_price, product_desc, goods_type, goods_spec, order_num, is_delete, created, modified, create_time, update_time, goods_name, goods_model from GOODS_MESSAGES
+
+
+
+
+
+
+
+
+ insert into GOODS_MESSAGES
+
+ goods_code,
+ stock_id,
+ review_status,
+ product_title,
+ product_picture,
+ original_price,
+ product_desc,
+ goods_type,
+ goods_spec,
+ order_num,
+ is_delete,
+ created,
+ modified,
+ create_time,
+ update_time,
+ goods_name,
+ goods_model,
+
+
+ #{goodsCode},
+ #{stockId},
+ #{reviewStatus},
+ #{productTitle},
+ #{productPicture},
+ #{originalPrice},
+ #{productDesc},
+ #{goodsType},
+ #{goodsSpec},
+ #{orderNum},
+ #{isDelete},
+ #{created},
+ #{modified},
+ #{createTime},
+ #{updateTime},
+ #{goodsName},
+ #{goodsModel},
+
+
+
+
+ update GOODS_MESSAGES
+
+ goods_code = #{goodsCode},
+ stock_id = #{stockId},
+ review_status = #{reviewStatus},
+ product_title = #{productTitle},
+ product_picture = #{productPicture},
+ original_price = #{originalPrice},
+ product_desc = #{productDesc},
+ goods_type = #{goodsType},
+ goods_spec = #{goodsSpec},
+ order_num = #{orderNum},
+ is_delete = #{isDelete},
+ created = #{created},
+ modified = #{modified},
+ create_time = #{createTime},
+ update_time = #{updateTime},
+ goods_name = #{goodsName},
+ goods_model = #{goodsModel},
+
+ where id = #{id}
+
+
+
+ delete from GOODS_MESSAGES where id = #{id}
+
+
+
+ delete from GOODS_MESSAGES where id in
+
+ #{id}
+
+
\ No newline at end of file
diff --git a/sf-ui/src/api/goods/goods.js b/sf-ui/src/api/service/goods.js
similarity index 76%
rename from sf-ui/src/api/goods/goods.js
rename to sf-ui/src/api/service/goods.js
index 68f58bc..ce3cca2 100644
--- a/sf-ui/src/api/goods/goods.js
+++ b/sf-ui/src/api/service/goods.js
@@ -1,44 +1,44 @@
-import request from '@/utils/request'
-
-// 查询商品信息列表
-export function listGoods(query) {
- return request({
- url: '/goods/goods/list',
- method: 'get',
- params: query
- })
-}
-
-// 查询商品信息详细
-export function getGoods(id) {
- return request({
- url: '/goods/goods/' + id,
- method: 'get'
- })
-}
-
-// 新增商品信息
-export function addGoods(data) {
- return request({
- url: '/goods/goods',
- method: 'post',
- data: data
- })
-}
-
-// 修改商品信息
-export function updateGoods(data) {
- return request({
- url: '/goods/goods',
- method: 'put',
- data: data
- })
-}
-
-// 删除商品信息
-export function delGoods(id) {
- return request({
- url: '/goods/goods/' + id,
- method: 'delete'
- })
-}
+import request from '@/utils/request'
+
+// 查询商品信息列表
+export function listGoods(query) {
+ return request({
+ url: '/service/goods/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询商品信息详细
+export function getGoods(id) {
+ return request({
+ url: '/service/goods/' + id,
+ method: 'get'
+ })
+}
+
+// 新增商品信息
+export function addGoods(data) {
+ return request({
+ url: '/service/goods',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改商品信息
+export function updateGoods(data) {
+ return request({
+ url: '/service/goods',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除商品信息
+export function delGoods(id) {
+ return request({
+ url: '/service/goods/' + id,
+ method: 'delete'
+ })
+}
diff --git a/sf-ui/src/views/goods/goods/index.vue b/sf-ui/src/views/service/goods/index.vue
similarity index 67%
rename from sf-ui/src/views/goods/goods/index.vue
rename to sf-ui/src/views/service/goods/index.vue
index 819c794..c8bf789 100644
--- a/sf-ui/src/views/goods/goods/index.vue
+++ b/sf-ui/src/views/service/goods/index.vue
@@ -1,348 +1,423 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 搜索
- 重置
-
-
-
-
-
- 新增
-
-
- 修改
-
-
- 删除
-
-
- 导出
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 修改
- 删除
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{dict.label}}
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+
+
+
+
+ 新增
+
+
+ 修改
+
+
+ 删除
+
+
+ 导出
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 修改
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{dict.label}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{dict.label}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+