- 后端:更新 README

- 后端:重构部分代码
This commit is contained in:
YunaiV
2019-05-17 19:23:26 +08:00
parent 68027b9f16
commit dbf2a43924
108 changed files with 589 additions and 1017 deletions

View File

@@ -3,10 +3,10 @@ package cn.iocoder.mall.pay.application.controller.admins;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.pay.api.PayRefundService;
import cn.iocoder.mall.pay.api.PayTransactionService;
import cn.iocoder.mall.pay.api.bo.PayRefundBO;
import cn.iocoder.mall.pay.api.bo.PayRefundPageBO;
import cn.iocoder.mall.pay.api.bo.PayTransactionBO;
import cn.iocoder.mall.pay.api.dto.PayRefundPageDTO;
import cn.iocoder.mall.pay.api.bo.refund.PayRefundBO;
import cn.iocoder.mall.pay.api.bo.refund.PayRefundPageBO;
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO;
import cn.iocoder.mall.pay.api.dto.refund.PayRefundPageDTO;
import cn.iocoder.mall.pay.application.convert.PayRefundConvert;
import cn.iocoder.mall.pay.application.vo.admins.AdminsPayRefundPageVO;
import org.apache.dubbo.config.annotation.Reference;

View File

@@ -2,8 +2,8 @@ package cn.iocoder.mall.pay.application.controller.admins;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.pay.api.PayTransactionService;
import cn.iocoder.mall.pay.api.bo.PayTransactionPageBO;
import cn.iocoder.mall.pay.api.dto.PayTransactionPageDTO;
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionPageBO;
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionPageDTO;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.GetMapping;

View File

@@ -3,11 +3,14 @@ package cn.iocoder.mall.pay.application.controller.users;
import cn.iocoder.common.framework.util.HttpUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.pay.api.PayTransactionService;
import cn.iocoder.mall.pay.api.bo.PayTransactionBO;
import cn.iocoder.mall.pay.api.bo.PayTransactionSubmitBO;
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO;
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionSubmitBO;
import cn.iocoder.mall.pay.api.constant.PayChannelEnum;
import cn.iocoder.mall.pay.api.dto.PayTransactionSubmitDTO;
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionGetDTO;
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionSubmitDTO;
import cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.dubbo.config.annotation.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -18,8 +21,11 @@ import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import static cn.iocoder.common.framework.vo.CommonResult.success;
@RestController
@RequestMapping("users/transaction") // TODO 芋艿,理论来说,是用户无关的。这里先酱紫先~
@RequestMapping("users/transaction")
@Api("【用户】支付交易 API")
public class UsersPayTransactionController {
private Logger logger = LoggerFactory.getLogger(getClass());
@@ -28,23 +34,19 @@ public class UsersPayTransactionController {
private PayTransactionService payTransactionService;
@GetMapping("/get")
// TODO result 后面改下
public CommonResult<PayTransactionBO> get(@RequestParam("appId") String appId,
@RequestParam("orderId") String orderId) {
return payTransactionService.getTransaction(UserSecurityContextHolder.getContext().getUserId(), appId, orderId);
@ApiOperation("获得支付交易")
public CommonResult<PayTransactionBO> get(PayTransactionGetDTO payTransactionGetDTO) {
payTransactionGetDTO.setUserId(UserSecurityContextHolder.getContext().getUserId());
return success(payTransactionService.getTransaction(payTransactionGetDTO));
}
@PostMapping("/submit") // TODO api 注释
// TODO result 后面改下
@PostMapping("/submit")
@ApiOperation("提交支付交易")
public CommonResult<PayTransactionSubmitBO> submit(HttpServletRequest request,
@RequestParam("appId") String appId,
@RequestParam("orderId") String orderId,
@RequestParam("payChannel") Integer payChannel) {
PayTransactionSubmitDTO payTransactionSubmitDTO = new PayTransactionSubmitDTO()
.setAppId(appId).setOrderId(orderId).setPayChannel(payChannel)
.setCreateIp(HttpUtil.getIp(request));
PayTransactionSubmitDTO payTransactionSubmitDTO) {
payTransactionSubmitDTO.setCreateIp(HttpUtil.getIp(request));
// 提交支付提交
return payTransactionService.submitTransaction(payTransactionSubmitDTO);
return success(payTransactionService.submitTransaction(payTransactionSubmitDTO));
}
@PostMapping(value = "pingxx_pay_success", consumes = MediaType.APPLICATION_JSON_VALUE)
@@ -63,11 +65,7 @@ public class UsersPayTransactionController {
// JSONObject bodyObj = JSON.parseObject(sb.toString());
// bodyObj.put("webhookId", bodyObj.remove("id"));
// String body = bodyObj.toString();
CommonResult<Boolean> result = payTransactionService.updateTransactionPaySuccess(PayChannelEnum.PINGXX.getId(), sb.toString());
if (result.isError()) {
logger.error("[pingxxPaySuccess][message({}) result({})]", sb, result);
return "failure";
}
payTransactionService.updateTransactionPaySuccess(PayChannelEnum.PINGXX.getId(), sb.toString());
return "success";
}

View File

@@ -1,6 +1,6 @@
package cn.iocoder.mall.pay.application.convert;
import cn.iocoder.mall.pay.api.bo.PayRefundBO;
import cn.iocoder.mall.pay.api.bo.refund.PayRefundBO;
import cn.iocoder.mall.pay.application.vo.admins.AdminsPayRefundDetailVO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;

View File

@@ -1,7 +1,7 @@
package cn.iocoder.mall.pay.application.vo.admins;
import cn.iocoder.mall.pay.api.bo.PayRefundBO;
import cn.iocoder.mall.pay.api.bo.PayTransactionBO;
import cn.iocoder.mall.pay.api.bo.refund.PayRefundBO;
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO;
import lombok.Data;
import lombok.experimental.Accessors;

View File

@@ -1,10 +1,10 @@
package cn.iocoder.mall.pay.api;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.pay.api.bo.PayRefundPageBO;
import cn.iocoder.mall.pay.api.bo.PayRefundSubmitBO;
import cn.iocoder.mall.pay.api.dto.PayRefundPageDTO;
import cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO;
import cn.iocoder.mall.pay.api.bo.refund.PayRefundPageBO;
import cn.iocoder.mall.pay.api.bo.refund.PayRefundSubmitBO;
import cn.iocoder.mall.pay.api.dto.refund.PayRefundPageDTO;
import cn.iocoder.mall.pay.api.dto.refund.PayRefundSubmitDTO;
public interface PayRefundService {

View File

@@ -1,23 +1,24 @@
package cn.iocoder.mall.pay.api;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.pay.api.bo.PayTransactionBO;
import cn.iocoder.mall.pay.api.bo.PayTransactionPageBO;
import cn.iocoder.mall.pay.api.bo.PayTransactionSubmitBO;
import cn.iocoder.mall.pay.api.dto.PayTransactionCreateDTO;
import cn.iocoder.mall.pay.api.dto.PayTransactionPageDTO;
import cn.iocoder.mall.pay.api.dto.PayTransactionSubmitDTO;
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO;
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionPageBO;
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionSubmitBO;
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionCreateDTO;
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionGetDTO;
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionPageDTO;
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionSubmitDTO;
import java.util.Collection;
import java.util.List;
public interface PayTransactionService {
CommonResult<PayTransactionBO> getTransaction(Integer userId, String appId, String orderId);
PayTransactionBO getTransaction(PayTransactionGetDTO payTransactionGetDTO);
CommonResult<PayTransactionBO> createTransaction(PayTransactionCreateDTO payTransactionCreateDTO);
PayTransactionBO createTransaction(PayTransactionCreateDTO payTransactionCreateDTO);
CommonResult<PayTransactionSubmitBO> submitTransaction(PayTransactionSubmitDTO payTransactionSubmitDTO);
PayTransactionSubmitBO submitTransaction(PayTransactionSubmitDTO payTransactionSubmitDTO);
/**
* 更新交易支付成功
@@ -29,7 +30,7 @@ public interface PayTransactionService {
* 因为不同平台,能够提供的参数不同,所以使用 String 类型统一接收,然后在使用不同的 AbstractPaySDK 进行处理。
* @return 是否支付成功
*/
CommonResult<Boolean> updateTransactionPaySuccess(Integer payChannel, String params);
Boolean updateTransactionPaySuccess(Integer payChannel, String params);
List<PayTransactionBO> getTransactionList(Collection<Integer> ids);

View File

@@ -1,24 +0,0 @@
package cn.iocoder.mall.pay.api.bo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* 支付交易提交结果 BO
*/
@Data
@Accessors(chain = true)
public class PayTransactionSubmitBO implements Serializable {
/**
* 支付交易拓展单编号
*/
private Integer id;
/**
* 调用三方平台的响应结果
*/
private String invokeResponse;
}

View File

@@ -1,4 +1,4 @@
package cn.iocoder.mall.pay.api.bo;
package cn.iocoder.mall.pay.api.bo.refund;
import lombok.Data;
import lombok.experimental.Accessors;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.mall.pay.api.bo;
package cn.iocoder.mall.pay.api.bo.refund;
import lombok.Data;
import lombok.experimental.Accessors;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.mall.pay.api.bo;
package cn.iocoder.mall.pay.api.bo.refund;
import lombok.Data;
import lombok.experimental.Accessors;

View File

@@ -1,63 +1,48 @@
package cn.iocoder.mall.pay.api.bo;
package cn.iocoder.mall.pay.api.bo.transaction;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* 支付交易 BO
*/
@ApiModel("支付交易 BO")
@Data
@Accessors(chain = true)
public class PayTransactionBO implements Serializable {
/**
* 编号自增
*/
@ApiModelProperty(value = "交易编号", required = true, example = "POd4RC6a")
private Integer id;
/**
* 应用编号
*/
@ApiModelProperty(value = "应用编号", required = true, example = "POd4RC6a")
private String appId;
/**
* 发起交易的 IP
*/
@ApiModelProperty(value = "发起交易的 IP", required = true, example = "192.168.10.1")
private String createIp;
/**
* 业务线的订单编号
*
* 1. 使用 String 的原因是业务线可能使用 String 做为编号
* 2. 每个 appId orderId 唯一
*/
@ApiModelProperty(value = "订单号不能为空", required = true, example = "1024")
private String orderId;
/**
* 订单商品名
*/
@ApiModelProperty(value = "商品名", required = true, example = "芋道源码")
private String orderSubject;
/**
* 订单商品描述
*/
@ApiModelProperty(value = "订单商品描述", required = true, example = "绵啾啾的")
private String orderDescription;
/**
* 订单备注
*/
@ApiModelProperty(value = "订单商品备注", example = "绵啾啾的")
private String orderMemo;
/**
* 支付金额单位
*/
@ApiModelProperty(value = "支付金额,单位:分。", required = true, example = "10")
private Integer price;
/**
* 订单状态
*
* @see cn.iocoder.mall.pay.api.constant.PayTransactionStatusEnum
*/
@ApiModelProperty(value = "订单状态", required = true, example = "1", notes = "参见 PayTransactionStatusEnum 枚举")
private Integer status;
/**
* 交易过期时间
*/
@ApiModelProperty(value = "交易过期时间", required = true)
private Date expireTime;
/**
* 回调业务线完成时间
*/

View File

@@ -1,4 +1,4 @@
package cn.iocoder.mall.pay.api.bo;
package cn.iocoder.mall.pay.api.bo.transaction;
import lombok.Data;
import lombok.experimental.Accessors;

View File

@@ -0,0 +1,21 @@
package cn.iocoder.mall.pay.api.bo.transaction;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@ApiModel("支付交易提交结果 BO")
@Data
@Accessors(chain = true)
public class PayTransactionSubmitBO implements Serializable {
@ApiModelProperty(value = "支付交易拓展单编号", required = true, example = "1")
private Integer id;
@ApiModelProperty(value = "调用三方平台的响应结果", required = true)
private String invokeResponse;
}

View File

@@ -1,9 +1,13 @@
package cn.iocoder.mall.pay.api.constant;
import cn.iocoder.common.framework.core.IntArrayValuable;
import java.util.Arrays;
/**
* 支付通道
*/
public enum PayChannelEnum {
public enum PayChannelEnum implements IntArrayValuable {
WEIXIN_APP(100, "wx", "微信 App 支付"),
WEIXIN_PUB(101, "wxjs", "微信 JS API 支付"),
@@ -13,6 +17,8 @@ public enum PayChannelEnum {
PINGXX(9999, "ping++", "ping++ 支付"),
;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PayChannelEnum::getId).toArray();
/**
* 渠道编号
*/
@@ -44,4 +50,9 @@ public enum PayChannelEnum {
return name;
}
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@@ -1,37 +0,0 @@
package cn.iocoder.mall.pay.api.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 支付交易提交 DTO
*/
@Data
@Accessors(chain = true)
public class PayTransactionSubmitDTO {
/**
* 应用编号
*/
@NotEmpty(message = "应用编号不能为空")
private String appId;
/**
* 发起交易的 IP
*/
@NotEmpty(message = "IP 不能为空")
private String createIp;
/**
* 业务线的订单编号
*/
@NotEmpty(message = "订单号不能为空")
private String orderId;
/**
* 支付渠道
*/
@NotNull(message = "支付渠道")
private Integer payChannel;
}

View File

@@ -1,4 +1,4 @@
package cn.iocoder.mall.pay.api.dto;
package cn.iocoder.mall.pay.api.dto.refund;
import lombok.Data;
import lombok.experimental.Accessors;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.mall.pay.api.dto;
package cn.iocoder.mall.pay.api.dto.refund;
import lombok.Data;
import lombok.experimental.Accessors;

View File

@@ -1,5 +1,7 @@
package cn.iocoder.mall.pay.api.dto;
package cn.iocoder.mall.pay.api.dto.transaction;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.Length;
@@ -10,54 +12,43 @@ import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Date;
/**
* 支付交易创建 DTO
*/
@ApiModel("支付交易创建 DTO")
@Data
@Accessors(chain = true)
public class PayTransactionCreateDTO implements Serializable {
/**
* 应用编号
*/
@ApiModelProperty(value = "应用编号", required = true, example = "POd4RC6a")
@NotEmpty(message = "应用编号不能为空")
private String appId;
/**
* 发起交易的 IP
*/
@ApiModelProperty(value = "发起交易的 IP", required = true, example = "192.168.10.1")
@NotEmpty(message = "IP 不能为空")
private String createIp;
/**
* 业务线的订单编号
*/
@ApiModelProperty(value = "订单号不能为空", required = true, example = "1024")
@NotEmpty(message = "订单号不能为空")
private String orderId;
/**
* 订单商品名
*/
@ApiModelProperty(value = "商品名", required = true, example = "芋道源码")
@NotEmpty(message = "商品名不能为空")
@Length(max = 32, message = "商品名不能超过32")
private String orderSubject;
/**
* 订单商品描述
*/
@ApiModelProperty(value = "订单商品描述", required = true, example = "绵啾啾的")
@NotEmpty(message = "商品描述不能为空")
@Length(max = 128, message = "商品描述长度不能超过128")
private String orderDescription;
/**
* 订单备注
*/
@Length(max = 256, message = "商品描述长度不能超过256")
@ApiModelProperty(value = "订单商品备注", example = "绵啾啾的")
@Length(max = 256, message = "商品备注长度不能超过256")
private String orderMemo;
/**
* 支付金额单位
*/
@ApiModelProperty(value = "支付金额,单位:分。", required = true, example = "10")
@NotNull(message = "金额不能为空")
@DecimalMin(value = "0", inclusive = false, message = "金额必须大于零")
private Integer price;
/**
* 交易过期时间
*/
@ApiModelProperty(value = "交易过期时间", required = true)
@NotNull(message = "交易过期时间不能为空")
private Date expireTime;

View File

@@ -0,0 +1,28 @@
package cn.iocoder.mall.pay.api.dto.transaction;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@ApiModel("支付交易获得 DTO")
@Data
@Accessors(chain = true)
public class PayTransactionGetDTO {
@ApiModelProperty(value = "用户编号", required = true, example = "1", hidden = true) // hidden 的原因是Service DTO 自己传入,无需暴露的 Controller API 里
@NotNull(message = "用户编号不能为空")
private Integer userId;
@ApiModelProperty(value = "应用编号", required = true, example = "POd4RC6a")
@NotEmpty(message = "应用编号不能为空")
private String appId;
@ApiModelProperty(value = "订单号不能为空", required = true, example = "1024")
@NotEmpty(message = "订单号不能为空")
private String orderId;
}

View File

@@ -1,4 +1,4 @@
package cn.iocoder.mall.pay.api.dto;
package cn.iocoder.mall.pay.api.dto.transaction;
import lombok.Data;
import lombok.experimental.Accessors;

View File

@@ -0,0 +1,35 @@
package cn.iocoder.mall.pay.api.dto.transaction;
import cn.iocoder.common.framework.validator.InEnum;
import cn.iocoder.mall.pay.api.constant.PayChannelEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@ApiModel("支付交易提交 DTO")
@Data
@Accessors(chain = true)
public class PayTransactionSubmitDTO {
@ApiModelProperty(value = "应用编号", required = true, example = "POd4RC6a")
@NotEmpty(message = "应用编号不能为空")
private String appId;
@ApiModelProperty(value = "发起交易的 IP", required = true, example = "192.168.10.1", hidden = true) // hidden 的原因是Service DTO 自己传入,无需暴露的 Controller API 里
@NotEmpty(message = "IP 不能为空")
private String createIp;
@ApiModelProperty(value = "订单号", required = true, example = "1024")
@NotEmpty(message = "订单号不能为空")
private String orderId;
@ApiModelProperty(value = "支付渠道", required = true, example = "1", notes = "参见 PayChannelEnum 枚举")
@InEnum(value = PayChannelEnum.class, message = "支付渠道必须是 {value}")
@NotNull(message = "支付渠道")
private Integer payChannel;
}

View File

@@ -1,17 +1,20 @@
package cn.iocoder.mall.pay.biz.component;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.rpc.service.GenericService;
import cn.iocoder.common.framework.util.StringUtil;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import lombok.Data;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.rpc.service.GenericService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import java.util.List;
@Component
public class DubboReferencePool {
@@ -44,7 +47,8 @@ public class DubboReferencePool {
private String dubboApplicationName;
private ReferenceMeta createGenericService(String notifyUrl) {
String[] notifyUrlParts = notifyUrl.split("#");
// 使用 # 号分隔,格式为 服务名#方法名#版本号
List<String> notifyUrlParts = StringUtil.split(notifyUrl, "#");
// 创建 ApplicationConfig 对象
ApplicationConfig application = new ApplicationConfig();
application.setName(dubboApplicationName);
@@ -55,14 +59,14 @@ public class DubboReferencePool {
application.setRegistry(registry);
// 创建 ReferenceConfig 对象
ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
reference.setInterface(notifyUrlParts[0]); // 弱类型接口名
reference.setInterface(notifyUrlParts.get(0)); // 弱类型接口名
reference.setGeneric(true); // 声明为泛化接口
reference.setApplication(application);
// reference.setVersion("*"); // TODO 芋艿,后面要优化下。
reference.setVersion(notifyUrlParts.size() > 2 ? notifyUrlParts.get(2) : "1.0.0"); // 如果未配置服务的版本号,则默认使用 1.0.0
// 获得 GenericService 对象
GenericService genericService = reference.get();
// 构建最终的 ReferenceMeta 对象
return new ReferenceMeta(reference, genericService, notifyUrlParts[1]);
return new ReferenceMeta(reference, genericService, notifyUrlParts.get(1));
}
public ReferenceMeta getReferenceMeta(String notifyUrl) {

View File

@@ -1,7 +1,7 @@
package cn.iocoder.mall.pay.biz.convert;
import cn.iocoder.mall.pay.api.bo.PayRefundBO;
import cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO;
import cn.iocoder.mall.pay.api.bo.refund.PayRefundBO;
import cn.iocoder.mall.pay.api.dto.refund.PayRefundSubmitDTO;
import cn.iocoder.mall.pay.biz.dataobject.PayRefundDO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;

View File

@@ -1,8 +1,8 @@
package cn.iocoder.mall.pay.biz.convert;
import cn.iocoder.mall.pay.api.bo.PayTransactionBO;
import cn.iocoder.mall.pay.api.dto.PayTransactionCreateDTO;
import cn.iocoder.mall.pay.api.dto.PayTransactionSubmitDTO;
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO;
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionCreateDTO;
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionSubmitDTO;
import cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO;
import cn.iocoder.mall.pay.biz.dataobject.PayTransactionExtensionDO;
import org.mapstruct.Mapper;

View File

@@ -18,6 +18,7 @@ import java.util.Date;
topic = PayRefundSuccessMessage.TOPIC,
consumerGroup = "pay-consumer-group-" + PayRefundSuccessMessage.TOPIC
)
@Deprecated // 艿艿:突然发现,业务方实际无需回调。参考了 https://help.youzan.com/displaylist/detail_4_998 的文章。业务方,只要记录下退款单号,进行关联即可。
public class PayRefundSuccessConsumer extends AbstractPayNotifySuccessConsumer<PayRefundSuccessMessage>
implements RocketMQListener<PayRefundSuccessMessage> {

View File

@@ -2,7 +2,6 @@ package cn.iocoder.mall.pay.biz.service;
import cn.iocoder.common.framework.constant.CommonStatusEnum;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.pay.api.constant.PayErrorCodeEnum;
import cn.iocoder.mall.pay.biz.dao.PayAppMapper;
import cn.iocoder.mall.pay.biz.dataobject.PayAppDO;
@@ -15,17 +14,17 @@ public class PayAppServiceImpl {
@Autowired
private PayAppMapper payAppMapper;
public CommonResult<PayAppDO> validPayApp(String appId) {
public PayAppDO validPayApp(String appId) {
PayAppDO payAppDO = payAppMapper.selectById(appId);
// 校验是否存在
if (payAppDO == null) {
return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_APP_NOT_FOUND.getCode());
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_APP_NOT_FOUND.getCode());
}
// 校验是否禁用
if (CommonStatusEnum.DISABLE.getValue().equals(payAppDO.getStatus())) {
return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_APP_IS_DISABLE.getCode());
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_APP_IS_DISABLE.getCode());
}
return CommonResult.success(payAppDO);
return payAppDO;
}
}
}

View File

@@ -27,6 +27,7 @@ public class PayNotifyServiceImpl {
@Resource
private RocketMQTemplate rocketMQTemplate;
@Deprecated // 参见 PayRefundSuccessConsumer 类的说明
public void addRefundNotifyTask(PayRefundDO refund) {
PayNotifyTaskDO payTransactionNotifyTask = this.createBasePayNotifyTaskDO(refund.getAppId(), refund.getNotifyUrl())
.setType(PayNotifyType.REFUND.getValue());

View File

@@ -5,13 +5,13 @@ import cn.iocoder.common.framework.util.MathUtil;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.pay.api.PayRefundService;
import cn.iocoder.mall.pay.api.bo.PayRefundPageBO;
import cn.iocoder.mall.pay.api.bo.PayRefundSubmitBO;
import cn.iocoder.mall.pay.api.bo.refund.PayRefundPageBO;
import cn.iocoder.mall.pay.api.bo.refund.PayRefundSubmitBO;
import cn.iocoder.mall.pay.api.constant.PayErrorCodeEnum;
import cn.iocoder.mall.pay.api.constant.PayRefundStatus;
import cn.iocoder.mall.pay.api.constant.PayTransactionStatusEnum;
import cn.iocoder.mall.pay.api.dto.PayRefundPageDTO;
import cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO;
import cn.iocoder.mall.pay.api.dto.refund.PayRefundPageDTO;
import cn.iocoder.mall.pay.api.dto.refund.PayRefundSubmitDTO;
import cn.iocoder.mall.pay.biz.client.AbstractPaySDK;
import cn.iocoder.mall.pay.biz.client.PaySDKFactory;
import cn.iocoder.mall.pay.biz.client.RefundSuccessBO;
@@ -51,13 +51,9 @@ public class PayRefundServiceImpl implements PayRefundService {
private RocketMQTemplate rocketMQTemplate;
@Override
@SuppressWarnings("Duplicates")
public CommonResult<PayRefundSubmitBO> submitRefund(PayRefundSubmitDTO payRefundSubmitDTO) {
// 校验 App 是否有效
CommonResult<PayAppDO> appResult = payAppService.validPayApp(payRefundSubmitDTO.getAppId());
if (appResult.isError()) {
return CommonResult.error(appResult);
}
PayAppDO payAppDO = payAppService.validPayApp(payRefundSubmitDTO.getAppId());
// 获得 PayTransactionDO ,并校验其是否存在
PayTransactionDO payTransaction = payTransactionService.getTransaction(payRefundSubmitDTO.getAppId(), payRefundSubmitDTO.getOrderId());
if (payTransaction == null) { // 是否存在
@@ -82,7 +78,7 @@ public class PayRefundServiceImpl implements PayRefundService {
.setTransactionId(payTransaction.getId())
.setRefundCode(generateTransactionCode()) // TODO 芋艿,后续调整
.setStatus(PayRefundStatus.WAITING.getValue())
.setNotifyUrl(appResult.getData().getRefundNotifyUrl())
.setNotifyUrl(payAppDO.getRefundNotifyUrl())
.setRefundChannel(payTransaction.getPayChannel());
payRefundDO.setCreateTime(new Date());
payRefundMapper.insert(payRefundDO);

View File

@@ -5,14 +5,15 @@ import cn.iocoder.common.framework.util.MathUtil;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.pay.api.PayTransactionService;
import cn.iocoder.mall.pay.api.bo.PayTransactionBO;
import cn.iocoder.mall.pay.api.bo.PayTransactionPageBO;
import cn.iocoder.mall.pay.api.bo.PayTransactionSubmitBO;
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO;
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionPageBO;
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionSubmitBO;
import cn.iocoder.mall.pay.api.constant.PayErrorCodeEnum;
import cn.iocoder.mall.pay.api.constant.PayTransactionStatusEnum;
import cn.iocoder.mall.pay.api.dto.PayTransactionCreateDTO;
import cn.iocoder.mall.pay.api.dto.PayTransactionPageDTO;
import cn.iocoder.mall.pay.api.dto.PayTransactionSubmitDTO;
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionCreateDTO;
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionGetDTO;
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionPageDTO;
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionSubmitDTO;
import cn.iocoder.mall.pay.biz.client.AbstractPaySDK;
import cn.iocoder.mall.pay.biz.client.PaySDKFactory;
import cn.iocoder.mall.pay.biz.client.TransactionSuccessBO;
@@ -68,23 +69,21 @@ public class PayTransactionServiceImpl implements PayTransactionService {
}
@Override
public CommonResult<PayTransactionBO> getTransaction(Integer userId, String appId, String orderId) {
PayTransactionDO payTransaction = payTransactionMapper.selectByAppIdAndOrderId(appId, orderId);
public PayTransactionBO getTransaction(PayTransactionGetDTO payTransactionGetDTO) {
PayTransactionDO payTransaction = payTransactionMapper.selectByAppIdAndOrderId(payTransactionGetDTO.getAppId(),
payTransactionGetDTO.getOrderId());
if (payTransaction == null) {
return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode());
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode());
}
// TODO 芋艿 userId 的校验
return CommonResult.success(PayTransactionConvert.INSTANCE.convert(payTransaction));
return PayTransactionConvert.INSTANCE.convert(payTransaction);
}
@Override
@SuppressWarnings("Duplicates")
public CommonResult<PayTransactionBO> createTransaction(PayTransactionCreateDTO payTransactionCreateDTO) {
public PayTransactionBO createTransaction(PayTransactionCreateDTO payTransactionCreateDTO) {
// 校验 App
CommonResult<PayAppDO> appResult = payAppService.validPayApp(payTransactionCreateDTO.getAppId());
if (appResult.isError()) {
return CommonResult.error(appResult);
}
PayAppDO payAppDO = payAppService.validPayApp(payTransactionCreateDTO.getAppId());
// 插入 PayTransactionDO
PayTransactionDO payTransaction = payTransactionMapper.selectByAppIdAndOrderId(
payTransactionCreateDTO.getAppId(), payTransactionCreateDTO.getOrderId());
@@ -95,31 +94,28 @@ public class PayTransactionServiceImpl implements PayTransactionService {
} else {
payTransaction = PayTransactionConvert.INSTANCE.convert(payTransactionCreateDTO);
payTransaction.setStatus(PayTransactionStatusEnum.WAITING.getValue())
.setNotifyUrl(appResult.getData().getNotifyUrl());
.setNotifyUrl(payAppDO.getNotifyUrl());
payTransaction.setCreateTime(new Date());
payTransactionMapper.insert(payTransaction);
}
// 返回成功
return CommonResult.success(PayTransactionConvert.INSTANCE.convert(payTransaction));
return PayTransactionConvert.INSTANCE.convert(payTransaction);
}
@Override
@SuppressWarnings("Duplicates")
public CommonResult<PayTransactionSubmitBO> submitTransaction(PayTransactionSubmitDTO payTransactionSubmitDTO) {
public PayTransactionSubmitBO submitTransaction(PayTransactionSubmitDTO payTransactionSubmitDTO) {
// TODO 校验支付渠道是否有效
// 校验 App 是否有效
CommonResult<PayAppDO> appResult = payAppService.validPayApp(payTransactionSubmitDTO.getAppId());
if (appResult.isError()) {
return CommonResult.error(appResult);
}
payAppService.validPayApp(payTransactionSubmitDTO.getAppId());
// 获得 PayTransactionDO ,并校验其是否存在
PayTransactionDO payTransaction = payTransactionMapper.selectByAppIdAndOrderId(
payTransactionSubmitDTO.getAppId(), payTransactionSubmitDTO.getOrderId());
if (payTransaction == null) { // 是否存在
return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode());
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode());
}
if (!PayTransactionStatusEnum.WAITING.getValue().equals(payTransaction.getStatus())) { // 校验状态,必须是待支付
return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_WAITING.getCode());
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_WAITING.getCode());
}
// 插入 PayTransactionExtensionDO
PayTransactionExtensionDO payTransactionExtensionDO = PayTransactionConvert.INSTANCE.convert(payTransactionSubmitDTO)
@@ -131,33 +127,32 @@ public class PayTransactionServiceImpl implements PayTransactionService {
AbstractPaySDK paySDK = PaySDKFactory.getSDK(payTransactionSubmitDTO.getPayChannel());
CommonResult<String> invokeResult = paySDK.submitTransaction(payTransaction, payTransactionExtensionDO, null); // TODO 暂时传入 extra = null
if (invokeResult.isError()) {
return CommonResult.error(invokeResult);
throw ServiceExceptionUtil.exception(invokeResult.getCode(), invokeResult.getMessage());
}
// TODO 轮询三方接口,是否已经支付的任务
// 返回成功
PayTransactionSubmitBO payTransactionSubmitBO = new PayTransactionSubmitBO()
.setId(payTransactionExtensionDO.getId()).setInvokeResponse(invokeResult.getData());
return CommonResult.success(payTransactionSubmitBO);
return new PayTransactionSubmitBO().setId(payTransactionExtensionDO.getId())
.setInvokeResponse(invokeResult.getData());
}
@Override
@Transactional
public CommonResult<Boolean> updateTransactionPaySuccess(Integer payChannel, String params) {
public Boolean updateTransactionPaySuccess(Integer payChannel, String params) {
// TODO 芋艿,记录回调日志
// 解析传入的参数,成 TransactionSuccessBO 对象
AbstractPaySDK paySDK = PaySDKFactory.getSDK(payChannel);
CommonResult<TransactionSuccessBO> paySuccessResult = paySDK.parseTransactionSuccessParams(params);
if (paySuccessResult.isError()) {
return CommonResult.error(paySuccessResult);
throw ServiceExceptionUtil.exception(paySuccessResult.getCode(), paySuccessResult.getMessage());
}
// TODO 芋艿,先最严格的校验。即使调用方重复调用,实际哪个订单已经被重复回调的支付,也返回 false 。也没问题,因为实际已经回调成功了。
// 1.1 查询 PayTransactionExtensionDO
PayTransactionExtensionDO extension = payTransactionExtensionMapper.selectByTransactionCode(paySuccessResult.getData().getTransactionCode());
if (extension == null) {
return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_NOT_FOUND.getCode());
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_NOT_FOUND.getCode());
}
if (!PayTransactionStatusEnum.WAITING.getValue().equals(extension.getStatus())) { // 校验状态,必须是待支付
return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_STATUS_IS_NOT_WAITING.getCode());
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_STATUS_IS_NOT_WAITING.getCode());
}
// 1.2 更新 PayTransactionExtensionDO
PayTransactionExtensionDO updatePayTransactionExtension = new PayTransactionExtensionDO()
@@ -172,7 +167,7 @@ public class PayTransactionServiceImpl implements PayTransactionService {
// 2.1 判断 PayTransactionDO 是否处于待支付
PayTransactionDO transaction = payTransactionMapper.selectById(extension.getTransactionId());
if (transaction == null) {
return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode());
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode());
}
if (!PayTransactionStatusEnum.WAITING.getValue().equals(transaction.getStatus())) { // 校验状态,必须是待支付
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_WAITING.getCode());
@@ -191,10 +186,10 @@ public class PayTransactionServiceImpl implements PayTransactionService {
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_WAITING.getCode());
}
logger.info("[updateTransactionPaySuccess][PayTransactionDO({}) 更新为已支付]", transaction.getId());
// 3 新增 PayNotifyTaskDO
payNotifyService.addTransactionNotifyTask(transaction, extension);
// 3 新增 PayNotifyTaskDO 注释原因,参见 PayRefundSuccessConsumer 类。
// payNotifyService.addTransactionNotifyTask(transaction, extension);
// 返回结果
return CommonResult.success(true);
return true;
}
@Override

View File

@@ -1,7 +1,7 @@
package cn.iocoder.mall.pay.biz.service;
import cn.iocoder.mall.pay.api.PayRefundService;
import cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO;
import cn.iocoder.mall.pay.api.dto.refund.PayRefundSubmitDTO;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -1,10 +1,6 @@
package cn.iocoder.mall.pay.biz.service;
import cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;