From b754fad9d004b02e6164208bbb21d44133a782d9 Mon Sep 17 00:00:00 2001
From: wangpengfei <1928057482@qq.com>
Date: Fri, 29 Mar 2024 17:15:02 +0800
Subject: [PATCH] =?UTF-8?q?=E9=80=80=E6=AC=BE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 6 +-
.../java/com/yxt/pay/api/refund/Refund.java | 8 +
.../com/yxt/pay/api/refund/RefundOrder.java | 43 +++
.../yxt/pay/api/refund/RefundOrderDto.java | 20 +
.../com/yxt/pay/api/refund/RefundOrderVo.java | 19 +
.../pay/api/refund/WXRefundOrderReqVo.java | 53 +++
.../pay/api/refund/WXRefundOrderRespVo.java | 71 ++++
.../yxt/pay/biz/refund/WxRefundMapper.java | 13 +
.../com/yxt/pay/biz/refund/WxRefundMapper.xml | 15 +
.../com/yxt/pay/biz/refund/WxRefundRest.java | 49 +++
.../yxt/pay/biz/refund/WxRefundService.java | 365 ++++++++++++++++++
src/main/resources/cert/apiclient_cert.p12 | Bin 0 -> 2782 bytes
src/main/resources/cert/apiclient_cert.pem | 25 ++
src/main/resources/cert/apiclient_key.pem | 28 ++
14 files changed, 714 insertions(+), 1 deletion(-)
create mode 100644 src/main/java/com/yxt/pay/api/refund/Refund.java
create mode 100644 src/main/java/com/yxt/pay/api/refund/RefundOrder.java
create mode 100644 src/main/java/com/yxt/pay/api/refund/RefundOrderDto.java
create mode 100644 src/main/java/com/yxt/pay/api/refund/RefundOrderVo.java
create mode 100644 src/main/java/com/yxt/pay/api/refund/WXRefundOrderReqVo.java
create mode 100644 src/main/java/com/yxt/pay/api/refund/WXRefundOrderRespVo.java
create mode 100644 src/main/java/com/yxt/pay/biz/refund/WxRefundMapper.java
create mode 100644 src/main/java/com/yxt/pay/biz/refund/WxRefundMapper.xml
create mode 100644 src/main/java/com/yxt/pay/biz/refund/WxRefundRest.java
create mode 100644 src/main/java/com/yxt/pay/biz/refund/WxRefundService.java
create mode 100644 src/main/resources/cert/apiclient_cert.p12
create mode 100644 src/main/resources/cert/apiclient_cert.pem
create mode 100644 src/main/resources/cert/apiclient_key.pem
diff --git a/pom.xml b/pom.xml
index 95047d9..620afd0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -36,7 +36,11 @@
org.springframework.cloud
spring-cloud-starter-openfeign
-
+
+ com.github.wechatpay-apiv3
+ wechatpay-java
+ 0.2.11
+
junit
diff --git a/src/main/java/com/yxt/pay/api/refund/Refund.java b/src/main/java/com/yxt/pay/api/refund/Refund.java
new file mode 100644
index 0000000..6423c1e
--- /dev/null
+++ b/src/main/java/com/yxt/pay/api/refund/Refund.java
@@ -0,0 +1,8 @@
+package com.yxt.pay.api.refund;
+
+/**
+ * @author wangpengfei
+ * @date 2024/3/25 15:03
+ */
+public class Refund {
+}
diff --git a/src/main/java/com/yxt/pay/api/refund/RefundOrder.java b/src/main/java/com/yxt/pay/api/refund/RefundOrder.java
new file mode 100644
index 0000000..500d62c
--- /dev/null
+++ b/src/main/java/com/yxt/pay/api/refund/RefundOrder.java
@@ -0,0 +1,43 @@
+package com.yxt.pay.api.refund;
+
+import com.yxt.common.base.utils.StringRandom;
+import com.yxt.common.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * @author wangpengfei
+ * @date 2024/3/28 9:47
+ */
+@Data
+public class RefundOrder extends BaseEntity {
+ private String outTradeNo;//订单编号
+ private int source;//来源 0云菜窖
+ private String name;//商品名
+ private String amount;//金额
+ private String openId;//
+ private String returnUrl;//业务回调
+ private String orderSid;//支付订单sid
+ private String reason;//退款原因
+
+
+ public String getTime() {
+ SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
+ return format.format(new Date());
+ }
+
+ public RefundOrder(int source) {
+ String Randomstr = StringRandom.getRandomString(15);
+ if (source == 0) {//云菜窖
+ outTradeNo = "YCJ" + getTime() + Randomstr;
+
+ } else if (source == 1) {
+
+ } else if (source == 2) {
+
+ }
+ this.source = source;
+ }
+}
diff --git a/src/main/java/com/yxt/pay/api/refund/RefundOrderDto.java b/src/main/java/com/yxt/pay/api/refund/RefundOrderDto.java
new file mode 100644
index 0000000..8fce446
--- /dev/null
+++ b/src/main/java/com/yxt/pay/api/refund/RefundOrderDto.java
@@ -0,0 +1,20 @@
+package com.yxt.pay.api.refund;
+
+import lombok.Data;
+
+/**
+ * @author wangpengfei
+ * @date 2024/3/28 9:57
+ */
+@Data
+public class RefundOrderDto {
+ private String outTradeNo;//订单编号
+ private int source;//来源 0云菜窖
+ private String name;//商品名
+ private String amount;//金额
+ private String openId;//
+ private String returnUrl;//业务回调
+ private String orderSid;//支付订单sid
+ private String reason;//退款原因
+ private String state;//1退款申请 2退款通过
+}
diff --git a/src/main/java/com/yxt/pay/api/refund/RefundOrderVo.java b/src/main/java/com/yxt/pay/api/refund/RefundOrderVo.java
new file mode 100644
index 0000000..2a645f5
--- /dev/null
+++ b/src/main/java/com/yxt/pay/api/refund/RefundOrderVo.java
@@ -0,0 +1,19 @@
+package com.yxt.pay.api.refund;
+
+import lombok.Data;
+
+/**
+ * @author wangpengfei
+ * @date 2024/3/28 9:57
+ */
+@Data
+public class RefundOrderVo {
+ private String outTradeNo;//订单编号
+ private String source;//来源 0云菜窖
+ private String name;//商品名
+ private String amount;//金额
+ private String openId;//
+ private String returnUrl;//业务回调
+ private String orderSid;//支付订单sid
+ private String reason;//退款原因
+}
diff --git a/src/main/java/com/yxt/pay/api/refund/WXRefundOrderReqVo.java b/src/main/java/com/yxt/pay/api/refund/WXRefundOrderReqVo.java
new file mode 100644
index 0000000..3152833
--- /dev/null
+++ b/src/main/java/com/yxt/pay/api/refund/WXRefundOrderReqVo.java
@@ -0,0 +1,53 @@
+package com.yxt.pay.api.refund;
+
+import lombok.Data;
+
+/**
+ * @author wangpengfei
+ * @date 2024/3/25 15:49
+ */
+@Data
+public class WXRefundOrderReqVo {
+ /**
+ * 微信支付订单号,微信支付订单号和商家订单号二选一
+ */
+// @Schema(description = "微信支付订单号")
+ private String transactionId;
+
+ /**
+ * 商家订单号,对应 out_trade_no,
+ */
+// @Schema(description = "商家订单号")
+ private String orderId;
+
+ /**
+ * 商户退款单号,对应out_refund_no
+ */
+// @Schema(description = "商户退款单号")
+ private String outRefundNo;
+
+ /**
+ * 退款原因,选填
+ */
+// @Schema(description = "退款原因")
+ private String reason;
+
+ /**
+ * 回调地址
+ */
+// @Schema(description = "回调地址")
+ private String notify;
+
+ /**
+ * 退款金额
+ */
+// @Schema(description = "退款金额")
+ private Integer refundMoney;
+
+ /**
+ * 原订单金额,必填
+ */
+// @Schema(description = "原订单金额")
+ private Integer totalMoney;
+
+}
diff --git a/src/main/java/com/yxt/pay/api/refund/WXRefundOrderRespVo.java b/src/main/java/com/yxt/pay/api/refund/WXRefundOrderRespVo.java
new file mode 100644
index 0000000..df6b167
--- /dev/null
+++ b/src/main/java/com/yxt/pay/api/refund/WXRefundOrderRespVo.java
@@ -0,0 +1,71 @@
+package com.yxt.pay.api.refund;
+
+import lombok.Data;
+
+/**
+ * @author wangpengfei
+ * @date 2024/3/25 15:51
+ */
+@Data
+public class WXRefundOrderRespVo {
+ /**
+ * 微信支付退款号
+ */
+// @Schema(description = "微信支付退款号")
+ private String refundId;
+
+ /**
+ * 商户退款单号
+ */
+// @Schema(description = "商户退款单号")
+ private String outRefundNo;
+
+ /**
+ * 微信支付订单号
+ */
+// @Schema(description = "微信支付订单号")
+ private String transactionId;
+
+ /**
+ * 商户订单号
+ */
+// @Schema(description = "商户订单号")
+ private String outTradeNo;
+
+ /**
+ * 退款渠道
+ */
+// @Schema(description = "退款渠道")
+ private String channel;
+
+ /**
+ * 退款入账账户
+ */
+// @Schema(description = "退款入账账户")
+ private String userReceivedAccount;
+
+ /**
+ * 退款成功时间
+ */
+// @Schema(description = "退款成功时间")
+ private String successTime;
+
+ /**
+ * 退款创建时间
+ */
+// @Schema(description = "退款创建时间")
+ private String createTime;
+
+ /**
+ * 退款状态
+ */
+// @Schema(description = "退款状态")
+ private String status;
+
+ /**
+ * 资金账户
+ */
+// @Schema(description = "资金账户")
+ private String fundsAccount;
+
+}
diff --git a/src/main/java/com/yxt/pay/biz/refund/WxRefundMapper.java b/src/main/java/com/yxt/pay/biz/refund/WxRefundMapper.java
new file mode 100644
index 0000000..ced96bb
--- /dev/null
+++ b/src/main/java/com/yxt/pay/biz/refund/WxRefundMapper.java
@@ -0,0 +1,13 @@
+package com.yxt.pay.biz.refund;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.yxt.pay.api.refund.RefundOrder;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @author wangpengfei
+ * @date 2024/3/25 15:02
+ */
+@Mapper
+public interface WxRefundMapper extends BaseMapper {
+}
diff --git a/src/main/java/com/yxt/pay/biz/refund/WxRefundMapper.xml b/src/main/java/com/yxt/pay/biz/refund/WxRefundMapper.xml
new file mode 100644
index 0000000..29fd460
--- /dev/null
+++ b/src/main/java/com/yxt/pay/biz/refund/WxRefundMapper.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/yxt/pay/biz/refund/WxRefundRest.java b/src/main/java/com/yxt/pay/biz/refund/WxRefundRest.java
new file mode 100644
index 0000000..f90cb3b
--- /dev/null
+++ b/src/main/java/com/yxt/pay/biz/refund/WxRefundRest.java
@@ -0,0 +1,49 @@
+package com.yxt.pay.biz.refund;
+
+import com.yxt.common.core.domain.BaseEntity;
+import com.yxt.common.core.result.ResultBean;
+import com.yxt.pay.api.refund.RefundOrder;
+import com.yxt.pay.api.refund.RefundOrderDto;
+import com.yxt.pay.api.refund.WXRefundOrderReqVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @author wangpengfei
+ * @date 2024/3/25 15:02
+ */
+@RestController
+@RequestMapping("refund")
+public class WxRefundRest {
+ @Autowired
+ WxRefundService refundService;
+
+
+
+ @PostMapping("/createRefundOrder" )
+ public ResultBean createRefundOrder(@RequestBody RefundOrderDto refundOrderDto) {
+ return refundService.createRefundOrder(refundOrderDto);
+ }
+
+
+
+ @PostMapping("/reviewRefund" )
+ public ResultBean reviewRefundById(@RequestParam String orderSid) throws Exception {
+ return refundService.refund(orderSid);
+ }
+ /**
+ * 微信退款回调
+ * @return R
+ */
+// @Operation(summary = "微信退款回调" , description = "微信退款回调" )
+// @SysLog("微信退款回调" )
+ @PostMapping("/payNotify")
+ public ResultBean refundPayNotify(HttpServletRequest request) throws Exception {
+ ResultBean rb=new ResultBean();
+ refundService.refundNotify(request);//注意:回调接口需要暴露到公网上,且要放开token验证
+ return rb.success();
+ }
+
+}
diff --git a/src/main/java/com/yxt/pay/biz/refund/WxRefundService.java b/src/main/java/com/yxt/pay/biz/refund/WxRefundService.java
new file mode 100644
index 0000000..ed97fbc
--- /dev/null
+++ b/src/main/java/com/yxt/pay/biz/refund/WxRefundService.java
@@ -0,0 +1,365 @@
+package com.yxt.pay.biz.refund;
+import cn.hutool.core.bean.BeanUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.wechat.pay.java.core.Config;
+import com.wechat.pay.java.core.RSAAutoCertificateConfig;
+import com.wechat.pay.java.core.exception.ServiceException;
+import com.wechat.pay.java.core.notification.NotificationConfig;
+import com.wechat.pay.java.core.notification.NotificationParser;
+import com.wechat.pay.java.core.notification.RequestParam;
+import com.wechat.pay.java.service.partnerpayments.app.model.Transaction;
+import com.wechat.pay.java.service.refund.RefundService;
+import com.wechat.pay.java.service.refund.model.*;
+import com.yxt.common.base.service.MybatisBaseService;
+import com.yxt.common.core.result.ResultBean;
+import com.yxt.pay.api.order.PayOrder;
+import com.yxt.pay.api.refund.RefundOrder;
+import com.yxt.pay.api.refund.RefundOrderDto;
+import com.yxt.pay.api.refund.WXRefundOrderReqVo;
+import com.yxt.pay.api.refund.WXRefundOrderRespVo;
+import com.yxt.pay.api.wxpay.WxPayVo;
+import com.yxt.pay.biz.order.OrderService;
+import com.yxt.pay.utils.UrlComponent;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.wechat.pay.java.core.http.Constant.*;
+
+/**
+ * @author wangpengfei
+ * @date 2024/3/25 15:02
+ */
+@Service
+@Slf4j
+public class WxRefundService extends MybatisBaseService {
+
+ @Autowired
+ private UrlComponent urlComponent;
+ @Autowired
+ private OrderService orderService;
+ @Value("${wx.api-key}")
+ String apiKey;
+ @Value("${wx.mch-serial-no}")
+ String mchSerialNo;
+ @Value("${wx.key-path}")
+ String keyPath;
+ @Value("${wx.mch-id}")
+ String mchId;
+
+ public static int source;
+
+
+
+ public ResultBean createRefundOrder(RefundOrderDto refundOrderDto){
+ ResultBean rb=new ResultBean();
+ RefundOrder refundOrder=new RefundOrder(refundOrderDto.getSource());
+ BeanUtil.copyProperties(refundOrderDto,refundOrder,"id","sid");
+ baseMapper.insert(refundOrder);
+ return rb.success().setData(refundOrder);
+
+ }
+ /**
+ * 功能描述:
+ * 〈微信退款〉
+ * @Param: [req]
+ * @Return: [void]
+ * @Author: whl
+ * @Date: 2023/10/12 15:46
+ */
+ public ResultBean refund(String orderSid) throws Exception {
+ ResultBean rb = ResultBean.fireFail();
+ try {
+ PayOrder payOrder=orderService.getOne(new QueryWrapper().eq("sid",orderSid));
+ WxPayVo wxPayVo=new WxPayVo(payOrder.getSource());
+ source=payOrder.getSource();
+ // 使用自动更新平台证书的RSA配置
+ // 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
+ Config config =
+ new RSAAutoCertificateConfig.Builder()
+ .merchantId(mchId)
+ //使用 SDK 不需要计算请求签名和验证应答签名
+ // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
+ .privateKeyFromPath(keyPath)
+ .merchantSerialNumber(mchSerialNo)
+ .apiV3Key(apiKey)
+ .build();
+ // 构建退款service
+ RefundService service = new RefundService.Builder().config(config).build();
+ // request.setXxx(val)设置所需参数,具体参数可见Request定义
+ //构建退款请求
+ CreateRequest request = new CreateRequest();
+ //构建订单金额信息
+ AmountReq amountReq = new AmountReq();
+// PayOrder payOrder=orderService.getOne(new QueryWrapper().eq("sid",orderSid));
+ RefundOrder refundOrder=baseMapper.selectOne(new QueryWrapper().eq("orderSid",payOrder.getSid()));
+ //退款金额
+ amountReq.setRefund(Long.valueOf(payOrder.getTotalTee()));
+// amountReq.setRefund(Long.valueOf("1"));
+ //原订单金额
+ amountReq.setTotal(Long.valueOf(payOrder.getTotalTee()));
+// amountReq.setTotal(Long.valueOf("1"));
+ //货币类型(默认人民币)
+ amountReq.setCurrency("CNY");
+ request.setAmount(amountReq);
+ //商户退款单号
+ request.setOutRefundNo(String.valueOf(payOrder.getOutTradeNo()));
+// request.setOutRefundNo(String.valueOf("ceshi"));
+ request.setOutTradeNo(refundOrder.getOutTradeNo());
+// request.setOutTradeNo("ceshi");
+ request.setReason(refundOrder.getReason());
+// request.setReason("ceshi");
+ //退款通知回调地址
+// request.setNotifyUrl(wxPayV3Bean.getRefundNotifyUrl());
+ request.setNotifyUrl(urlComponent.getDoMainUrl() + "order/payNotify");
+ // 调用退款方法,得到应答
+ // 调用微信sdk接口
+ Refund refund = service.create(request);
+ //接收退款返回参数
+ Refund refundResponse = new Refund();
+ refundResponse.setStatus(refund.getStatus());
+ System.out.println(refund);;
+ if (refundResponse.getStatus().equals(Status.SUCCESS)){
+ //说明退款成功,开始接下来的业务操作
+// WXRefundOrderRespVo refundOrderRespVO = new WXRefundOrderRespVo();
+ //你的业务代码
+ return rb.success().setData(refund);
+ }else{
+
+ return rb.setMsg("申请退款失败").setData(refund);
+ }
+ }catch (Exception e){
+ e.printStackTrace();
+ return rb.setMsg("退款失败,error=" + e.getMessage());
+// throw new ResultException(ResultEnum.ERROR,e.toString());
+ }
+ }
+
+ /**
+ * 功能描述:
+ * 〈微信退款回调〉
+ * @Param: [request, response]
+ * @Return: [void]
+ * @Author: whl
+ * @Date: 2023/10/13 10:46
+ */
+ public void refundNotify(HttpServletRequest request) throws Exception {
+ try {
+ WxPayVo wxPayVo=new WxPayVo(0);
+ //读取请求体的信息
+ ServletInputStream inputStream = request.getInputStream();
+ StringBuffer stringBuffer = new StringBuffer();
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
+ String s;
+ //读取回调请求体
+ while ((s = bufferedReader.readLine()) != null) {
+ stringBuffer.append(s);
+ }
+ String s1 = stringBuffer.toString();
+ String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
+ String nonce = request.getHeader(WECHAT_PAY_NONCE);
+ String signType = request.getHeader("Wechatpay-Signature-Type");
+ String serialNo = request.getHeader(WECHAT_PAY_SERIAL);
+ String signature = request.getHeader(WECHAT_PAY_SIGNATURE);
+ // 如果已经初始化了 RSAAutoCertificateConfig,可直接使用
+ // 没有的话,则构造一个
+// log.error(JSON.toJSONString(wxPayV3Bean));
+ NotificationConfig config = new RSAAutoCertificateConfig.Builder()
+ .merchantId(mchId)
+ .privateKeyFromPath(keyPath)
+ .merchantSerialNumber(mchSerialNo)
+ .apiV3Key(apiKey)
+ .build();
+ // 初始化 NotificationParser
+ NotificationParser parser = new NotificationParser(config);
+ RequestParam requestParam=new RequestParam.Builder()
+ .serialNumber(serialNo)
+ .nonce(nonce)
+ .signature(signature)
+ .timestamp(timestamp)
+ // 若未设置signType,默认值为 WECHATPAY2-SHA256-RSA2048
+ .signType(signType)
+ .body(s1)
+ .build();
+ RefundNotification parse = parser.parse(requestParam, RefundNotification.class);
+ System.out.println("退款回调结果: " + parse);
+ //parse.getRefundStatus().equals("SUCCESS");说明退款成功
+ if (parse.getRefundStatus().equals(Transaction.TradeStateEnum.SUCCESS)){
+ //你的业务代码
+
+ }else{
+
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+
+
+// //url 微信退款请求地址 data 请求参数
+// public static String doRefund(String url, String data) throws Exception {
+//
+// KeyStore keyStore = KeyStore.getInstance("PKCS12");
+// // 指定证书路径
+// String path = "/cert/apiclient_cert.p12";
+// ClassPathResource classPathResource = new ClassPathResource(path);
+//
+// //读取项目存放的PKCS12证书文件
+// InputStream stream = classPathResource.getInputStream();
+// String mchId = "自己的商户id";
+// try {
+// //指定PKCS12的初始密码为商户ID
+// keyStore.load(stream, mchId.toCharArray());
+// } finally {
+// stream.close();
+// }
+// SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
+// //指定TLS版本
+// SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslcontext,new String[] { "TLSv1"},null,SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
+// //设置httpclient的SSLSocketFactory
+// CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
+// try {
+// HttpPost httpost = new HttpPost(url); // 设置响应头信息
+// httpost.addHeader("Connection", "keep-alive");
+// httpost.addHeader("Accept", "*/*");
+// httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
+// httpost.addHeader("Host", "api.mch.weixin.qq.com");
+// httpost.addHeader("X-Requested-With", "XMLHttpRequest");
+// httpost.addHeader("Cache-Control", "max-age=0");
+// httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
+// httpost.setEntity(new StringEntity(data, "UTF-8"));
+// CloseableHttpResponse response = httpclient.execute(httpost);
+// try {
+// HttpEntity entity = response.getEntity();
+// String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
+// EntityUtils.consume(entity);
+// return jsonStr;
+// } finally {
+// response.close();
+// }
+// } finally {
+// httpclient.close();
+// }
+// }
+// /**
+// * 退款
+// * @param orderPrice 订单金额(分)
+// * @param refundPrice 退款金额(分)
+// * @param refundMark 退款备注
+// * @param out_trade_no 退款商家订单号
+// * @return
+// * @throws Exception
+// */
+// public static String refund(Integer orderPrice,Integer refundPrice,String refundMark,String out_trade_no) throws Exception {
+// Map params = new HashMap<>();
+//
+// String outRefundNo = GenerateNum.getInstance().GenerateOrder();//可以自定义一个类来随机生成退款单号等等
+//
+// params.put("appid", "小程序Appid");
+// params.put("mch_id", "商户号");
+// //商户订单号
+// params.put("out_trade_no", out_trade_no);
+// //商户退款单号
+// params.put("out_refund_no", outRefundNo);
+// //总金额
+// params.put("total_fee", String.valueOf(orderPrice));
+// //退款金额
+// params.put("refund_fee", String.valueOf(refundPrice));
+// //退款原因
+// params.put("refund_desc", refundMark);
+// //退款结果回调地址
+// params.put("notify_url", "回调域名");
+// //随机字符串
+// params.put("nonce_str", WXPayUtil.generateNonceStr());//使用微信随机字符串生成
+// //生成sign
+// String sign = WXPayUtil.generateSignature(params, "自己的商户密钥");
+// params.put("sign", sign);
+// //微信申请退款接口
+// String wx_refund_url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
+//
+// String xmlStr = WXPayUtil.mapToXml(params);//转换成xml格式
+// System.out.println(xmlStr);
+// //发送双向证书请求给微信
+// String resultXmlStr = doRefund(wx_refund_url, xmlStr);
+// System.out.println(resultXmlStr);
+// // 将返回的字符串转成Map集合
+// Map resultMap = WXPayUtil.xmlToMap(resultXmlStr);//转成map格式
+//
+// Map map = new HashMap<>();
+// if ("SUCCESS".equalsIgnoreCase(resultMap.get("result_code"))) {
+// System.out.println("------申请退款成功,正在退款中----");
+// //申请微信退款接口返回success,但是退款到账还需要时间;
+// map.put("success", "REFUNDS");
+// return "1";
+// } else {
+// map.put("success", resultMap.get("err_code_des"));
+// System.out.println("-------------退款失败-------------------" + resultMap.get("err_code_des"));
+// return "2";
+// }
+// }
+// /*
+// * 退款订单结果查询
+// * 生成签名的xml
+// * @return
+// * */
+// public static String selRefundOrder(String out_trade_no) {
+// // 封装需要的信息
+// Map payMap = new HashMap();
+// String nonceStr = WXPayUtil.generateNonceStr();
+// try {
+// // 1. 拼接下单地址参数
+// Map param = new HashMap();
+// param.put("appid", "小程序appid");
+// param.put("mch_id", "商户id");
+// param.put("out_trade_no", out_trade_no); // 随机字符串
+// param.put("nonce_str", nonceStr); // 账单类型
+// param.put("sign_type", "MD5"); // 签名类型
+// // 生成签名,官方默认MD5+商户秘钥+参数信息
+// String sign = WXPayUtil.generateSignature(param, "商户密钥");
+// param.put("sign", sign);
+// // 将所有参数转换为xml形式
+// String xmlParam = WXPayUtil.mapToXml(param);
+//
+// // 2. 发送请求
+// HttpClient1 httpClient1 = new HttpClient1("https://api.mch.weixin.qq.com/pay/refundquery");
+// httpClient1.setHttps(true);// https协议
+// httpClient1.setXmlParam(xmlParam);
+// httpClient1.post();
+// // 获取结果
+// String xmlResult = httpClient1.getContent();
+// System.out.println(xmlResult);
+// if (xmlResult.indexOf("SUCCESS") != -1) { // 只要执行了下单接口,都会包含SUCCESS的
+// Map map = WXPayUtil.xmlToMap(xmlResult);
+// if (map.get("refund_fee").equals(map.get("total_fee"))){
+// System.out.println(out_trade_no+"退款"+map.get("refund_fee")+"成功到"+map.get("refund_recv_accout_0"));
+// return "1";
+// }else {
+// System.out.println(out_trade_no+"退款"+map.get("refund_fee")+"部分到"+map.get("refund_recv_accout_0"));
+// return "2";
+// }
+//
+// }else {
+// System.out.println(out_trade_no+"退款失败,不存在");
+// return "3";
+// }
+//
+// } catch (Exception e) {
+// e.printStackTrace();
+// payMap.put("msg", out_trade_no+"签名生成错误");
+// return "签名失败";
+// }
+// }
+
+}
diff --git a/src/main/resources/cert/apiclient_cert.p12 b/src/main/resources/cert/apiclient_cert.p12
new file mode 100644
index 0000000000000000000000000000000000000000..9af0641863916ad9f11c78ef4e23baf5df6418ef
GIT binary patch
literal 2782
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