持续完善业务逻辑
This commit is contained in:
parent
0fcd26552b
commit
991ab454f1
@ -1,4 +1,7 @@
|
|||||||
|
# 当前支付模块写的并不完善,请根据自己的业务需求进行修改
|
||||||
|
# 回调地址使用的内网穿透http://e2vca6.natappfree.cc
|
||||||
pay:
|
pay:
|
||||||
|
# https://doc.shouqianba.com/zh-cn/
|
||||||
sqb:
|
sqb:
|
||||||
enabled: false
|
enabled: false
|
||||||
appId: "appId"
|
appId: "appId"
|
||||||
@ -9,12 +12,14 @@ pay:
|
|||||||
vendorKey: "vendorKey"
|
vendorKey: "vendorKey"
|
||||||
publicKey: classpath:pay/sqb/sqb_public_key.pem
|
publicKey: classpath:pay/sqb/sqb_public_key.pem
|
||||||
notifyUrl: http://e2vca6.natappfree.cc/pay/sqb/notify
|
notifyUrl: http://e2vca6.natappfree.cc/pay/sqb/notify
|
||||||
|
# https://opendocs.alipay.com/open/02np95
|
||||||
alipay:
|
alipay:
|
||||||
enabled: false
|
enabled: false
|
||||||
appId: appid
|
appId: appid
|
||||||
appPrivateKey: classpath:pay/alipay/alipay_private_key.pem
|
appPrivateKey: classpath:pay/alipay/alipay_private_key.pem
|
||||||
alipayPublicKey: classpath:pay/alipay/alipay_public_key.pem
|
alipayPublicKey: classpath:pay/alipay/alipay_public_key.pem
|
||||||
notifyUrl: http://e2vca6.natappfree.cc/alipay/notify
|
notifyUrl: http://e2vca6.natappfree.cc/alipay/notify
|
||||||
|
# https://github.com/wechatpay-apiv3/wechatpay-java
|
||||||
wechat:
|
wechat:
|
||||||
enabled: false
|
enabled: false
|
||||||
appId: appid
|
appId: appid
|
||||||
@ -22,5 +27,5 @@ pay:
|
|||||||
privateKeyPath: classpath:pay/wx/apiclient_key.pem
|
privateKeyPath: classpath:pay/wx/apiclient_key.pem
|
||||||
merchantId: merchantId
|
merchantId: merchantId
|
||||||
merchantSerialNumber: merchantSerialNumber
|
merchantSerialNumber: merchantSerialNumber
|
||||||
# 回调地址,此处使用的内网穿透http://e2vca6.natappfree.cc
|
|
||||||
notifyUrl: http://e2vca6.natappfree.cc/pay/wechat/notify
|
notifyUrl: http://e2vca6.natappfree.cc/pay/wechat/notify
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.ruoyi.auth.controller;
|
package com.ruoyi.auth.controller;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -16,13 +17,27 @@ import com.ruoyi.common.core.domain.AjaxResult;
|
|||||||
import com.ruoyi.common.core.domain.model.LoginBody;
|
import com.ruoyi.common.core.domain.model.LoginBody;
|
||||||
import com.ruoyi.common.core.domain.model.RegisterBody;
|
import com.ruoyi.common.core.domain.model.RegisterBody;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/auth/<channel>") // dySms mail
|
@RequestMapping("/auth/{channel}") // dySms mail
|
||||||
public class TfaController extends BaseController {
|
public class TfaController extends BaseController {
|
||||||
|
|
||||||
@Autowired
|
@Autowired(required = false)
|
||||||
Map<String, TfaService> tfaServiceMap;
|
Map<String, TfaService> tfaServiceMap;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
if (tfaServiceMap == null) {
|
||||||
|
tfaServiceMap = new HashMap<>();
|
||||||
|
logger.warn("请注意,没有加载任何双认证服务");
|
||||||
|
} else {
|
||||||
|
tfaServiceMap.forEach((k, v) -> {
|
||||||
|
logger.info("已加载双认证服务 {}", k);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/send/bind")
|
@PostMapping("/send/bind")
|
||||||
public AjaxResult send(@PathVariable String channel, @RequestBody LoginBody loginBody) {
|
public AjaxResult send(@PathVariable String channel, @RequestBody LoginBody loginBody) {
|
||||||
TfaService tfaService = tfaServiceMap.get(channel + "AuthService");
|
TfaService tfaService = tfaServiceMap.get(channel + "AuthService");
|
||||||
|
@ -8,6 +8,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import com.alipay.easysdk.factory.Factory;
|
import com.alipay.easysdk.factory.Factory;
|
||||||
|
import com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse;
|
||||||
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
|
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
|
||||||
import com.ruoyi.common.exception.ServiceException;
|
import com.ruoyi.common.exception.ServiceException;
|
||||||
import com.ruoyi.pay.alipay.service.IAliPayService;
|
import com.ruoyi.pay.alipay.service.IAliPayService;
|
||||||
@ -63,14 +64,63 @@ public class AliPayService implements IAliPayService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String query(PayOrder payOrder) {
|
public PayOrder query(PayOrder payOrder) {
|
||||||
// TODO Auto-generated method stub
|
try {
|
||||||
throw new UnsupportedOperationException("Unimplemented method 'query'");
|
// 使用支付宝SDK查询订单状态
|
||||||
|
com.alipay.easysdk.payment.common.models.AlipayTradeQueryResponse response = Factory.Payment.Common()
|
||||||
|
.query(payOrder.getOrderNumber());
|
||||||
|
|
||||||
|
// 根据查询结果更新订单状态
|
||||||
|
if ("10000".equals(response.code)) {
|
||||||
|
String tradeStatus = response.tradeStatus;
|
||||||
|
String orderStatus = "";
|
||||||
|
|
||||||
|
// 根据支付宝交易状态映射到系统订单状态
|
||||||
|
switch (tradeStatus) {
|
||||||
|
case "TRADE_SUCCESS":
|
||||||
|
case "TRADE_FINISHED":
|
||||||
|
orderStatus = "已支付";
|
||||||
|
break;
|
||||||
|
case "WAIT_BUYER_PAY":
|
||||||
|
orderStatus = "待支付";
|
||||||
|
break;
|
||||||
|
case "TRADE_CLOSED":
|
||||||
|
orderStatus = "已关闭";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
orderStatus = "未知状态";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新订单信息
|
||||||
|
payOrderService.updateStatus(payOrder.getOrderNumber(), orderStatus);
|
||||||
|
} else {
|
||||||
|
throw new ServiceException("查询支付宝订单失败:" + response.subMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return payOrder;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ServiceException("查询支付宝订单异常:" + e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String refund(PayOrder payOrder) {
|
public PayOrder refund(PayOrder payOrder) {
|
||||||
// TODO Auto-generated method stub
|
try {
|
||||||
throw new UnsupportedOperationException("Unimplemented method 'refund'");
|
// 使用支付宝SDK进行退款
|
||||||
|
AlipayTradeRefundResponse response = Factory.Payment.Common().refund(
|
||||||
|
payOrder.getOrderNumber(),
|
||||||
|
payOrder.getActualAmount());
|
||||||
|
|
||||||
|
// 处理退款结果
|
||||||
|
if ("10000".equals(response.code)) {
|
||||||
|
payOrderService.updateStatus(payOrder.getOrderNumber(), "已退款");
|
||||||
|
} else {
|
||||||
|
throw new ServiceException("支付宝退款失败:" + response.subMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return payOrder;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ServiceException("支付宝退款异常:" + e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,10 +23,15 @@ public class PayOrder extends BaseEntity {
|
|||||||
private Long orderId;
|
private Long orderId;
|
||||||
|
|
||||||
/** 订单号 */
|
/** 订单号 */
|
||||||
@Schema(title = "订单号")
|
@Schema(title = "商户订单号")
|
||||||
@Excel(name = "订单号")
|
@Excel(name = "商户订单号")
|
||||||
private String orderNumber;
|
private String orderNumber;
|
||||||
|
|
||||||
|
/** 第三方订单号 */
|
||||||
|
@Schema(title = "第三方订单号")
|
||||||
|
@Excel(name = "第三方订单号")
|
||||||
|
private String thirdNumber;
|
||||||
|
|
||||||
/** 订单状态 */
|
/** 订单状态 */
|
||||||
@Schema(title = "订单状态")
|
@Schema(title = "订单状态")
|
||||||
@Excel(name = "订单状态")
|
@Excel(name = "订单状态")
|
||||||
@ -68,6 +73,14 @@ public class PayOrder extends BaseEntity {
|
|||||||
return orderNumber;
|
return orderNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setThirdNumber(String thirdNumber) {
|
||||||
|
this.thirdNumber = thirdNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getThirdNumber() {
|
||||||
|
return thirdNumber;
|
||||||
|
}
|
||||||
|
|
||||||
public void setOrderStatus(String orderStatus) {
|
public void setOrderStatus(String orderStatus) {
|
||||||
this.orderStatus = orderStatus;
|
this.orderStatus = orderStatus;
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ public interface PayService {
|
|||||||
|
|
||||||
String notify(HttpServletRequest servletRequest, HttpServletResponse response);
|
String notify(HttpServletRequest servletRequest, HttpServletResponse response);
|
||||||
|
|
||||||
String query(PayOrder payOrder);
|
PayOrder query(PayOrder payOrder);
|
||||||
|
|
||||||
String refund(PayOrder payOrder);
|
PayOrder refund(PayOrder payOrder);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<resultMap type="PayOrder" id="PayOrderResult">
|
<resultMap type="PayOrder" id="PayOrderResult">
|
||||||
<result property="orderId" column="order_id" />
|
<result property="orderId" column="order_id" />
|
||||||
<result property="orderNumber" column="order_number" />
|
<result property="orderNumber" column="order_number" />
|
||||||
|
<result property="thirdNumber" column="third_number" />
|
||||||
<result property="orderStatus" column="order_status" />
|
<result property="orderStatus" column="order_status" />
|
||||||
<result property="totalAmount" column="total_amount" />
|
<result property="totalAmount" column="total_amount" />
|
||||||
<result property="actualAmount" column="actual_amount" />
|
<result property="actualAmount" column="actual_amount" />
|
||||||
@ -27,6 +28,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<include refid="selectPayOrderVo"/>
|
<include refid="selectPayOrderVo"/>
|
||||||
<where>
|
<where>
|
||||||
<if test="orderNumber != null and orderNumber != ''"> and order_number = #{orderNumber}</if>
|
<if test="orderNumber != null and orderNumber != ''"> and order_number = #{orderNumber}</if>
|
||||||
|
<if test="thirdNumber != null and thirdNumber != ''"> and third_number = #{thirdNumber}</if>
|
||||||
<if test="orderStatus != null and orderStatus != ''"> and order_status = #{orderStatus}</if>
|
<if test="orderStatus != null and orderStatus != ''"> and order_status = #{orderStatus}</if>
|
||||||
<if test="totalAmount != null and totalAmount != ''"> and total_amount = #{totalAmount}</if>
|
<if test="totalAmount != null and totalAmount != ''"> and total_amount = #{totalAmount}</if>
|
||||||
<if test="actualAmount != null and actualAmount != ''"> and actual_amount = #{actualAmount}</if>
|
<if test="actualAmount != null and actualAmount != ''"> and actual_amount = #{actualAmount}</if>
|
||||||
@ -44,6 +46,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
insert into pay_order
|
insert into pay_order
|
||||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
<if test="orderNumber != null">order_number,</if>
|
<if test="orderNumber != null">order_number,</if>
|
||||||
|
<if test="thirdNumber != null">third_number,</if>
|
||||||
<if test="orderStatus != null">order_status,</if>
|
<if test="orderStatus != null">order_status,</if>
|
||||||
<if test="totalAmount != null">total_amount,</if>
|
<if test="totalAmount != null">total_amount,</if>
|
||||||
<if test="actualAmount != null">actual_amount,</if>
|
<if test="actualAmount != null">actual_amount,</if>
|
||||||
@ -57,6 +60,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
</trim>
|
</trim>
|
||||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
<if test="orderNumber != null">#{orderNumber},</if>
|
<if test="orderNumber != null">#{orderNumber},</if>
|
||||||
|
<if test="thirdNumber != null">#{thirdNumber},</if>
|
||||||
<if test="orderStatus != null">#{orderStatus},</if>
|
<if test="orderStatus != null">#{orderStatus},</if>
|
||||||
<if test="totalAmount != null">#{totalAmount},</if>
|
<if test="totalAmount != null">#{totalAmount},</if>
|
||||||
<if test="actualAmount != null">#{actualAmount},</if>
|
<if test="actualAmount != null">#{actualAmount},</if>
|
||||||
@ -74,6 +78,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
update pay_order
|
update pay_order
|
||||||
<trim prefix="SET" suffixOverrides=",">
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
<if test="orderNumber != null">order_number = #{orderNumber},</if>
|
<if test="orderNumber != null">order_number = #{orderNumber},</if>
|
||||||
|
<if test="thirdNumber != null">third_number = #{thirdNumber},</if>
|
||||||
<if test="orderStatus != null">order_status = #{orderStatus},</if>
|
<if test="orderStatus != null">order_status = #{orderStatus},</if>
|
||||||
<if test="totalAmount != null">total_amount = #{totalAmount},</if>
|
<if test="totalAmount != null">total_amount = #{totalAmount},</if>
|
||||||
<if test="actualAmount != null">actual_amount = #{actualAmount},</if>
|
<if test="actualAmount != null">actual_amount = #{actualAmount},</if>
|
||||||
|
@ -28,18 +28,24 @@ import com.ruoyi.common.utils.SecurityUtils;
|
|||||||
import com.ruoyi.common.utils.http.HttpClientUtil;
|
import com.ruoyi.common.utils.http.HttpClientUtil;
|
||||||
import com.ruoyi.common.utils.sign.Md5Utils;
|
import com.ruoyi.common.utils.sign.Md5Utils;
|
||||||
import com.ruoyi.pay.domain.PayOrder;
|
import com.ruoyi.pay.domain.PayOrder;
|
||||||
|
import com.ruoyi.pay.service.IPayOrderService;
|
||||||
import com.ruoyi.pay.sqb.config.SqbConfig;
|
import com.ruoyi.pay.sqb.config.SqbConfig;
|
||||||
import com.ruoyi.pay.sqb.service.ISqbPayService;
|
import com.ruoyi.pay.sqb.service.ISqbPayService;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Service("sqbPayService")
|
@Service("sqbPayService")
|
||||||
@ConditionalOnProperty(prefix = "pay.sqb", name = "enabled", havingValue = "true")
|
@ConditionalOnProperty(prefix = "pay.sqb", name = "enabled", havingValue = "true")
|
||||||
public class SQBServiceImpl implements ISqbPayService {
|
public class SQBServiceImpl implements ISqbPayService {
|
||||||
@Autowired
|
@Autowired
|
||||||
private SqbConfig sqbConfig;
|
private SqbConfig sqbConfig;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IPayOrderService payOrderService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* http POST 请求
|
* http POST 请求
|
||||||
*
|
*
|
||||||
@ -146,7 +152,7 @@ public class SQBServiceImpl implements ISqbPayService {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public String refund(PayOrder payOrder) {
|
public PayOrder refund(PayOrder payOrder) {
|
||||||
String url = sqbConfig.getApiDomain() + "/upay/v2/refund";
|
String url = sqbConfig.getApiDomain() + "/upay/v2/refund";
|
||||||
JSONObject params = new JSONObject();
|
JSONObject params = new JSONObject();
|
||||||
try {
|
try {
|
||||||
@ -158,8 +164,14 @@ public class SQBServiceImpl implements ISqbPayService {
|
|||||||
|
|
||||||
String sign = getSign(params.toString() + sqbConfig.getTerminalKey());
|
String sign = getSign(params.toString() + sqbConfig.getTerminalKey());
|
||||||
String result = httpPost(url, params, sign, sqbConfig.getTerminalSn());
|
String result = httpPost(url, params, sign, sqbConfig.getTerminalSn());
|
||||||
|
JSONObject retObj = JSON.parseObject(result);
|
||||||
return result;
|
JSONObject bizResponse = retObj.getJSONObject("biz_response");
|
||||||
|
if ("REFUNDED".equals(bizResponse.getString("order_status"))) {
|
||||||
|
payOrderService.updateStatus(payOrder.getOrderNumber(), "已退款");
|
||||||
|
} else {
|
||||||
|
log.error("退款失败");
|
||||||
|
}
|
||||||
|
return payOrder;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -170,8 +182,8 @@ public class SQBServiceImpl implements ISqbPayService {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public String query(PayOrder payOrder) {
|
public PayOrder query(PayOrder payOrder) {
|
||||||
String url = sqbConfig.getApiDomain() + "/upay/v2/query";
|
String url = sqbConfig.getApiDomain() + "/upay/v2/query";
|
||||||
JSONObject params = new JSONObject();
|
JSONObject params = new JSONObject();
|
||||||
try {
|
try {
|
||||||
@ -185,8 +197,8 @@ public class SQBServiceImpl implements ISqbPayService {
|
|||||||
if (!"200".equals(resCode)) {
|
if (!"200".equals(resCode)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String responseStr = retObj.get("biz_response").toString();
|
// String responseStr = retObj.get("biz_response").toString();
|
||||||
return responseStr;
|
return payOrder;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.ruoyi.pay.controller;
|
package com.ruoyi.pay.controller;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -8,8 +9,8 @@ import org.springframework.web.bind.annotation.PathVariable;
|
|||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
|
||||||
import com.ruoyi.common.annotation.Anonymous;
|
import com.ruoyi.common.annotation.Anonymous;
|
||||||
import com.ruoyi.common.core.controller.BaseController;
|
import com.ruoyi.common.core.controller.BaseController;
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
@ -20,19 +21,35 @@ import com.ruoyi.pay.service.PayService;
|
|||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.Parameters;
|
import io.swagger.v3.oas.annotations.Parameters;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
@RequestMapping("/pay/<channel>")
|
@RequestMapping("/pay/{channel}")
|
||||||
|
@RestController
|
||||||
public class PayController extends BaseController {
|
public class PayController extends BaseController {
|
||||||
@Autowired
|
|
||||||
|
@Autowired(required = false)
|
||||||
private Map<String, PayService> payServiceMap; // alipay wechat sqb
|
private Map<String, PayService> payServiceMap; // alipay wechat sqb
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
if (payServiceMap == null) {
|
||||||
|
payServiceMap = new HashMap<>();
|
||||||
|
logger.warn("请注意,没有加载任何支付服务");
|
||||||
|
} else {
|
||||||
|
payServiceMap.forEach((k, v) -> {
|
||||||
|
logger.info("已加载支付服务 {}", k);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IPayOrderService payOrderService;
|
private IPayOrderService payOrderService;
|
||||||
|
|
||||||
@Operation(summary = "微信支付")
|
@Operation(summary = "微信支付")
|
||||||
@Parameters({
|
@Parameters({
|
||||||
|
@Parameter(name = "channel", description = "支付方式", required = true),
|
||||||
@Parameter(name = "orderNumber", description = "订单号", required = true)
|
@Parameter(name = "orderNumber", description = "订单号", required = true)
|
||||||
})
|
})
|
||||||
@GetMapping("/url/{orderNumber}")
|
@GetMapping("/url/{orderNumber}")
|
||||||
@ -44,6 +61,9 @@ public class PayController extends BaseController {
|
|||||||
|
|
||||||
@Anonymous
|
@Anonymous
|
||||||
@Operation(summary = "微信支付查询订单")
|
@Operation(summary = "微信支付查询订单")
|
||||||
|
@Parameters({
|
||||||
|
@Parameter(name = "channel", description = "支付方式", required = true)
|
||||||
|
})
|
||||||
@PostMapping("/notify")
|
@PostMapping("/notify")
|
||||||
public String notify(@PathVariable String channel, HttpServletRequest request, HttpServletResponse response)
|
public String notify(@PathVariable String channel, HttpServletRequest request, HttpServletResponse response)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@ -52,7 +72,8 @@ public class PayController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "查询支付状态")
|
@Operation(summary = "查询支付状态")
|
||||||
@Parameters(value = {
|
@Parameters({
|
||||||
|
@Parameter(name = "channel", description = "支付方式", required = true),
|
||||||
@Parameter(name = "orderNumber", description = "订单号", required = true)
|
@Parameter(name = "orderNumber", description = "订单号", required = true)
|
||||||
})
|
})
|
||||||
@PostMapping("/query/{orderNumber}")
|
@PostMapping("/query/{orderNumber}")
|
||||||
@ -64,13 +85,11 @@ public class PayController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/refund")
|
@PostMapping("/refund")
|
||||||
|
@Parameters({
|
||||||
|
@Parameter(name = "channel", description = "支付方式", required = true),
|
||||||
|
})
|
||||||
public AjaxResult refund(@PathVariable String channel, @RequestBody PayOrder payOrder) {
|
public AjaxResult refund(@PathVariable String channel, @RequestBody PayOrder payOrder) {
|
||||||
PayService payService = payServiceMap.get(channel + "PayService");
|
PayService payService = payServiceMap.get(channel + "PayService");
|
||||||
String refund = payService.refund(payOrder);
|
return success(payService.refund(payOrder));
|
||||||
if (refund == null) {
|
|
||||||
return error("退款失败");
|
|
||||||
}
|
|
||||||
Object parse = JSON.parse(refund);
|
|
||||||
return success(parse);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import org.springframework.core.io.Resource;
|
|||||||
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
|
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
|
||||||
import com.wechat.pay.java.core.notification.NotificationParser;
|
import com.wechat.pay.java.core.notification.NotificationParser;
|
||||||
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
|
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
|
||||||
|
import com.wechat.pay.java.service.refund.RefundService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 配置我们自己的信息
|
* 配置我们自己的信息
|
||||||
@ -26,79 +27,54 @@ import com.wechat.pay.java.service.payments.nativepay.NativePayService;
|
|||||||
@ConditionalOnProperty(prefix = "pay.wechat", name = "enabled", havingValue = "true")
|
@ConditionalOnProperty(prefix = "pay.wechat", name = "enabled", havingValue = "true")
|
||||||
public class WxPayConfig {
|
public class WxPayConfig {
|
||||||
|
|
||||||
|
/** 商户号 */
|
||||||
@Value("${pay.wechat.merchantId}")
|
@Value("${pay.wechat.merchantId}")
|
||||||
private String wxchantId;
|
private String merchantId;
|
||||||
|
|
||||||
|
/** 商户证书序列号 */
|
||||||
@Value("${pay.wechat.merchantSerialNumber}")
|
@Value("${pay.wechat.merchantSerialNumber}")
|
||||||
private String wxchantSerialNumber;
|
private String merchantSerialNumber;
|
||||||
|
|
||||||
|
/** 商户APIV3密钥 */
|
||||||
@Value("${pay.wechat.apiV3Key}")
|
@Value("${pay.wechat.apiV3Key}")
|
||||||
private String wxapiV3Key;
|
private String apiV3Key;
|
||||||
|
|
||||||
|
/** 商户API私钥路径 */
|
||||||
@Value("${pay.wechat.privateKeyPath}")
|
@Value("${pay.wechat.privateKeyPath}")
|
||||||
private String wxcertPath;
|
private String privateKeyPath;
|
||||||
|
|
||||||
@Value("${pay.wechat.appId}")
|
@Value("${pay.wechat.appId}")
|
||||||
private String appId;
|
private String appId;
|
||||||
|
|
||||||
@Value("${pay.wechat.notifyUrl}")
|
@Value("${pay.wechat.notifyUrl}")
|
||||||
private String notifyUrl;
|
private String notifyUrl;
|
||||||
|
|
||||||
@Bean
|
public String getMerchantId() {
|
||||||
public RSAAutoCertificateConfig wxpayBaseConfig() throws Exception {
|
return merchantId;
|
||||||
return new RSAAutoCertificateConfig.Builder()
|
|
||||||
.merchantId(getWxchantId())
|
|
||||||
.privateKeyFromPath(getWxcertPath())
|
|
||||||
.merchantSerialNumber(getWxchantSerialNumber())
|
|
||||||
.apiV3Key(getWxapiV3Key())
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
public void setMerchantId(String merchantId) {
|
||||||
public NativePayService nativePayService() throws Exception {
|
this.merchantId = merchantId;
|
||||||
return new NativePayService.Builder().config(wxpayBaseConfig()).build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
public String getMerchantSerialNumber() {
|
||||||
public NotificationParser notificationParser() throws Exception {
|
return merchantSerialNumber;
|
||||||
return new NotificationParser(wxpayBaseConfig());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
public void setMerchantSerialNumber(String merchantSerialNumber) {
|
||||||
private ApplicationContext applicationContext;
|
this.merchantSerialNumber = merchantSerialNumber;
|
||||||
|
|
||||||
public String getWxcertPath() throws Exception {
|
|
||||||
if (wxcertPath.startsWith("classpath:")) {
|
|
||||||
Resource resource = applicationContext.getResource(wxcertPath);
|
|
||||||
String tempFilePath = System.getProperty("java.io.tmpdir") + "/temp_wxcert.pem";
|
|
||||||
try (InputStream inputStream = resource.getInputStream()) {
|
|
||||||
Files.copy(inputStream, Paths.get(tempFilePath), StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
wxcertPath = tempFilePath;
|
|
||||||
} catch (Exception e) {
|
|
||||||
Files.deleteIfExists(Paths.get(tempFilePath));
|
|
||||||
throw new RuntimeException("微信支付证书文件读取失败", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return wxcertPath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getWxchantId() {
|
public String getApiV3Key() {
|
||||||
return wxchantId;
|
return apiV3Key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWxchantId(String wxchantId) {
|
public void setApiV3Key(String apiV3Key) {
|
||||||
this.wxchantId = wxchantId;
|
this.apiV3Key = apiV3Key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getWxchantSerialNumber() {
|
public void setPrivateKeyPath(String privateKeyPath) {
|
||||||
return wxchantSerialNumber;
|
this.privateKeyPath = privateKeyPath;
|
||||||
}
|
|
||||||
|
|
||||||
public void setWxchantSerialNumber(String wxchantSerialNumber) {
|
|
||||||
this.wxchantSerialNumber = wxchantSerialNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getWxapiV3Key() {
|
|
||||||
return wxapiV3Key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWxapiV3Key(String wxapiV3Key) {
|
|
||||||
this.wxapiV3Key = wxapiV3Key;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAppId() {
|
public String getAppId() {
|
||||||
@ -116,4 +92,48 @@ public class WxPayConfig {
|
|||||||
public void setNotifyUrl(String notifyUrl) {
|
public void setNotifyUrl(String notifyUrl) {
|
||||||
this.notifyUrl = notifyUrl;
|
this.notifyUrl = notifyUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RSAAutoCertificateConfig wxpayBaseConfig() throws Exception {
|
||||||
|
return new RSAAutoCertificateConfig.Builder()
|
||||||
|
.merchantId(getMerchantId())
|
||||||
|
.privateKeyFromPath(getPrivateKeyPath())
|
||||||
|
.merchantSerialNumber(getMerchantSerialNumber())
|
||||||
|
.apiV3Key(getApiV3Key())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public NativePayService nativePayService() throws Exception {
|
||||||
|
return new NativePayService.Builder().config(wxpayBaseConfig()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RefundService refundService() throws Exception {
|
||||||
|
return new RefundService.Builder().config(wxpayBaseConfig()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public NotificationParser notificationParser() throws Exception {
|
||||||
|
return new NotificationParser(wxpayBaseConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
public String getPrivateKeyPath() throws Exception {
|
||||||
|
if (privateKeyPath.startsWith("classpath:")) {
|
||||||
|
Resource resource = applicationContext.getResource(privateKeyPath);
|
||||||
|
String tempFilePath = System.getProperty("java.io.tmpdir") + "/temp_wxcert.pem";
|
||||||
|
try (InputStream inputStream = resource.getInputStream()) {
|
||||||
|
Files.copy(inputStream, Paths.get(tempFilePath), StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
privateKeyPath = tempFilePath;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Files.deleteIfExists(Paths.get(tempFilePath));
|
||||||
|
throw new RuntimeException("微信支付证书文件读取失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return privateKeyPath;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package com.ruoyi.pay.wx.service;
|
package com.ruoyi.pay.wx.service;
|
||||||
|
|
||||||
import com.ruoyi.pay.service.PayService;
|
import com.ruoyi.pay.service.PayService;
|
||||||
import com.wechat.pay.java.service.wexinpayscoreparking.model.Transaction;
|
|
||||||
|
|
||||||
public interface IWxPayService extends PayService {
|
public interface IWxPayService extends PayService {
|
||||||
public void callback(Transaction transaction);
|
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,20 @@ import com.ruoyi.pay.domain.PayOrder;
|
|||||||
import com.ruoyi.pay.service.IPayOrderService;
|
import com.ruoyi.pay.service.IPayOrderService;
|
||||||
import com.ruoyi.pay.wx.config.WxPayConfig;
|
import com.ruoyi.pay.wx.config.WxPayConfig;
|
||||||
import com.ruoyi.pay.wx.service.IWxPayService;
|
import com.ruoyi.pay.wx.service.IWxPayService;
|
||||||
|
import com.wechat.pay.java.core.exception.ServiceException;
|
||||||
import com.wechat.pay.java.core.notification.NotificationParser;
|
import com.wechat.pay.java.core.notification.NotificationParser;
|
||||||
import com.wechat.pay.java.core.notification.RequestParam;
|
import com.wechat.pay.java.core.notification.RequestParam;
|
||||||
|
import com.wechat.pay.java.service.payments.model.Transaction;
|
||||||
|
import com.wechat.pay.java.service.payments.model.Transaction.TradeStateEnum;
|
||||||
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
|
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
|
||||||
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
|
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
|
||||||
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
|
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
|
||||||
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
|
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
|
||||||
import com.wechat.pay.java.service.wexinpayscoreparking.model.Transaction;
|
import com.wechat.pay.java.service.payments.nativepay.model.QueryOrderByIdRequest;
|
||||||
|
import com.wechat.pay.java.service.refund.RefundService;
|
||||||
|
import com.wechat.pay.java.service.refund.model.CreateRequest;
|
||||||
|
import com.wechat.pay.java.service.refund.model.Refund;
|
||||||
|
import com.wechat.pay.java.service.refund.model.Status;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
@ -38,9 +45,8 @@ public class WxPayService implements IWxPayService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private NotificationParser notificationParser;
|
private NotificationParser notificationParser;
|
||||||
|
|
||||||
public void callback(Transaction transaction) {
|
@Autowired
|
||||||
|
private RefundService refundService;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String payUrl(PayOrder payOrder) {
|
public String payUrl(PayOrder payOrder) {
|
||||||
@ -49,7 +55,7 @@ public class WxPayService implements IWxPayService {
|
|||||||
amount.setTotal(Integer.parseInt(payOrder.getActualAmount()));
|
amount.setTotal(Integer.parseInt(payOrder.getActualAmount()));
|
||||||
request.setAmount(amount);
|
request.setAmount(amount);
|
||||||
request.setAppid(wxPayAppConfig.getAppId());
|
request.setAppid(wxPayAppConfig.getAppId());
|
||||||
request.setMchid(wxPayAppConfig.getWxchantId());
|
request.setMchid(wxPayAppConfig.getMerchantId());
|
||||||
request.setDescription(payOrder.getOrderContent());
|
request.setDescription(payOrder.getOrderContent());
|
||||||
request.setNotifyUrl(wxPayAppConfig.getNotifyUrl());
|
request.setNotifyUrl(wxPayAppConfig.getNotifyUrl());
|
||||||
request.setOutTradeNo(payOrder.getOrderNumber());
|
request.setOutTradeNo(payOrder.getOrderNumber());
|
||||||
@ -75,7 +81,7 @@ public class WxPayService implements IWxPayService {
|
|||||||
Transaction transaction = notificationParser.parse(requestParam, Transaction.class);
|
Transaction transaction = notificationParser.parse(requestParam, Transaction.class);
|
||||||
String orderNumber = transaction.getOutTradeNo();
|
String orderNumber = transaction.getOutTradeNo();
|
||||||
String otherOrderNumber = transaction.getTransactionId();
|
String otherOrderNumber = transaction.getTransactionId();
|
||||||
String orderState = transaction.getTradeState();
|
TradeStateEnum orderState = transaction.getTradeState();
|
||||||
System.out.println("orderNumber: " + orderNumber);
|
System.out.println("orderNumber: " + orderNumber);
|
||||||
System.out.println("otherOrderNumber: " + otherOrderNumber);
|
System.out.println("otherOrderNumber: " + otherOrderNumber);
|
||||||
System.out.println("orderState: " + orderState);
|
System.out.println("orderState: " + orderState);
|
||||||
@ -87,15 +93,32 @@ public class WxPayService implements IWxPayService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String query(PayOrder payOrder) {
|
public PayOrder query(PayOrder payOrder) {
|
||||||
// TODO Auto-generated method stub
|
QueryOrderByIdRequest queryRequest = new QueryOrderByIdRequest();
|
||||||
throw new UnsupportedOperationException("Unimplemented method 'query'");
|
queryRequest.setMchid(wxPayAppConfig.getMerchantId());
|
||||||
|
queryRequest.setTransactionId(payOrder.getOrderNumber());
|
||||||
|
try {
|
||||||
|
Transaction result = nativePayService.queryOrderById(queryRequest);
|
||||||
|
System.out.println(result.getTradeState());
|
||||||
|
} catch (ServiceException e) {
|
||||||
|
System.out.printf("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
|
||||||
|
System.out.printf("reponse body=[%s]\n", e.getResponseBody());
|
||||||
|
}
|
||||||
|
return payOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String refund(PayOrder payOrder) {
|
public PayOrder refund(PayOrder payOrder) {
|
||||||
// TODO Auto-generated method stub
|
CreateRequest request = new CreateRequest();
|
||||||
throw new UnsupportedOperationException("Unimplemented method 'refund'");
|
request.setTransactionId(payOrder.getOrderNumber());
|
||||||
|
request.setOutRefundNo(payOrder.getOrderNumber());
|
||||||
|
request.setOutTradeNo(payOrder.getOrderNumber());
|
||||||
|
Refund refund = refundService.create(request);
|
||||||
|
Status status = refund.getStatus();
|
||||||
|
if (status.equals(Status.SUCCESS)) {
|
||||||
|
payOrderService.updateStatus(payOrder.getOrderNumber(), "已退款");
|
||||||
|
}
|
||||||
|
return payOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ DROP TABLE IF EXISTS `pay_order`;
|
|||||||
CREATE TABLE `pay_order` (
|
CREATE TABLE `pay_order` (
|
||||||
order_id bigint NOT NULL AUTO_INCREMENT COMMENT '订单id',
|
order_id bigint NOT NULL AUTO_INCREMENT COMMENT '订单id',
|
||||||
order_number varchar(255) NULL DEFAULT NULL COMMENT '订单号',
|
order_number varchar(255) NULL DEFAULT NULL COMMENT '订单号',
|
||||||
|
third_number varchar(255) NULL DEFAULT NULL COMMENT '第三方订单号',
|
||||||
order_status varchar(255) NULL DEFAULT NULL COMMENT '订单状态',
|
order_status varchar(255) NULL DEFAULT NULL COMMENT '订单状态',
|
||||||
total_amount varchar(255) NULL DEFAULT NULL COMMENT '订单总金额',
|
total_amount varchar(255) NULL DEFAULT NULL COMMENT '订单总金额',
|
||||||
actual_amount varchar(255) NULL DEFAULT NULL COMMENT '实际支付金额',
|
actual_amount varchar(255) NULL DEFAULT NULL COMMENT '实际支付金额',
|
||||||
|
@ -5,6 +5,7 @@ DROP TABLE IF EXISTS pay_order;
|
|||||||
CREATE TABLE pay_order (
|
CREATE TABLE pay_order (
|
||||||
order_id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
order_id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||||
order_number varchar(255) NULL DEFAULT NULL,
|
order_number varchar(255) NULL DEFAULT NULL,
|
||||||
|
third_number varchar(255) NULL DEFAULT NULL,
|
||||||
order_status varchar(255) NULL DEFAULT NULL,
|
order_status varchar(255) NULL DEFAULT NULL,
|
||||||
total_amount varchar(255) NULL DEFAULT NULL,
|
total_amount varchar(255) NULL DEFAULT NULL,
|
||||||
actual_amount varchar(255) NULL DEFAULT NULL,
|
actual_amount varchar(255) NULL DEFAULT NULL,
|
||||||
@ -19,6 +20,7 @@ CREATE TABLE pay_order (
|
|||||||
|
|
||||||
COMMENT ON COLUMN pay_order.order_id IS '订单id';
|
COMMENT ON COLUMN pay_order.order_id IS '订单id';
|
||||||
COMMENT ON COLUMN pay_order.order_number IS '订单号';
|
COMMENT ON COLUMN pay_order.order_number IS '订单号';
|
||||||
|
COMMENT ON COLUMN pay_order.third_number IS '第三方订单号';
|
||||||
COMMENT ON COLUMN pay_order.order_status IS '订单状态';
|
COMMENT ON COLUMN pay_order.order_status IS '订单状态';
|
||||||
COMMENT ON COLUMN pay_order.total_amount IS '订单总金额';
|
COMMENT ON COLUMN pay_order.total_amount IS '订单总金额';
|
||||||
COMMENT ON COLUMN pay_order.actual_amount IS '实际支付金额';
|
COMMENT ON COLUMN pay_order.actual_amount IS '实际支付金额';
|
||||||
|
Loading…
Reference in New Issue
Block a user