海豚精灵:https://www.whhtjl.com;优课GO:https://mgo.whhtjl.com
相信大家已在网上找了各种资料,也看过了各种文档,对于整个流程我就不再重复啦,有疑惑的小伙伴可以移步微信开放平台查看详情,网页地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
我大概的说下我们项目中的业务逻辑:若当前用户是VIP用户,当前用户再次成功购买VIP卡后,将原有的且未用完的VIP卡费原路退还给用户;效果图如下所示:
重点代码如下所示:
我这里后端使用的SpringBoot,Maven项目,代码如下:
<!--公众号(包括订阅号和服务号) -->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>2.7.0</version>
</dependency>
<!--微信支付 -->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-pay</artifactId>
<version>3.0.0</version>
</dependency>
在application.properties中配置相关信息
微信APP支付这块是需要证书,大家自行去微信开放平台配置下载后放入resources目录下,可直接用classpath:xxxxxx.p12引入
#微信支付
wx.pay.appId=XXXXXXXXXXXXXXXXXXXXX
wx.pay.appSecret=XXXXXXXXXXXXXXXXXXXXX
wx.pay.mchId=XXXXXXXXXXXXXXXXXXXXX
wx.pay.mchKey=XXXXXXXXXXXXXXXXXXXXX
wx.pay.keyPath=classpath:apiclient_cert.p12
wx.pay.tradeType=APP
创建实体类
package com.ltf.config;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 微信支付商户基本信息
* @author xhz
*
*/
@Data
@Component
@ConfigurationProperties(prefix = "wx.pay")
public class WeChatPayProperties {
/**
* appId
*/
private String appId;
/**
* 公众平台密钥
*/
private String appSecret;
/**
* 商户号
*/
private String mchId;
/**
* 商户密钥
*/
private String mchKey;
/**
* 证书
*/
private String keyPath;
/**
* 交易类型
* <pre>
* JSAPI--公众号支付
* NATIVE--原生扫码支付
* APP--app支付
* </pre>
*/
private String tradeType;
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this,
ToStringStyle.MULTI_LINE_STYLE);
}
}
创建控制层
package com.ltf.controller;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.ltf.cache.CacheUtil;
import com.ltf.entity.User;
import com.ltf.utils.SingletonLoginUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import javax.servlet.http.HttpServletRequest;
/**
* 微信退款
* @author xhz
*
*/
@RestController
@RequestMapping(value = "/api/client/refund/")
@Slf4j
public class WeChatRefundController extends BaseController{
private static final String REFUND_SUCCESS = "SUCCESS";
@Autowired
private WxPayService wxPayService;
/**
* 微信退款
* @return
*/
@SuppressWarnings("static-access")
@PostMapping(value = "weChatRefund")
public JSONObject refund(@RequestParam("mobileCode") String mobileCode,@RequestParam("withdrawalAmount") String withdrawalAmount,HttpServletRequest request) {
try {
User user=SingletonLoginUtils.getLoginUser(request);
if(user!=null){
if(user.getIsAvailable()==2){
return this.formatJSON(500, "抱歉,冻结状态下无法提现!", null);
}else{
if(user.getMobile()!=null&&!"".equals(user.getMobile().trim())){
// 从缓存提取手机验证码
String mobileCodeNum = (String) CacheUtil.get(user.getMobile()+ "_mobileCodeNum_withdrawMoney");
if (!mobileCode.equals(mobileCodeNum) || mobileCodeNum == null) {
return this.formatJSON(500, "请输入正确的手机验证码!",null);
}else{
if(withdrawalAmount!=null&&!"".equals(withdrawalAmount.trim())){
//申请退款
WxPayRefundRequest refundInfo = WxPayRefundRequest.newBuilder()
//订单号
.outTradeNo("202006291442477005999225798514")
//退款订单号
.outRefundNo("202006291442477005999225798514")
//金额
.totalFee(yuanToFee(new BigDecimal(withdrawalAmount)))
//退款金额
.refundFee(yuanToFee(new BigDecimal(withdrawalAmount)))
//todo 回调地址
.notifyUrl("https://你的域名/api/client/refund/refundNotify")
.build();
WxPayRefundResult wxPayRefundResult;
wxPayRefundResult = wxPayService.refund(refundInfo);
//判断退款信息是否正确
if (REFUND_SUCCESS.equals(wxPayRefundResult.getReturnCode())
&& REFUND_SUCCESS.equals(wxPayRefundResult.getResultCode())) {
/**
* 系统内部业务逻辑
*/
//减掉可提现金额
return this.formatJSON(200, "OK", null);
}else{
return this.formatJSON(500, "提现失败!", null);
}
}else{
return this.formatJSON(500, "请填写提现金额!", null);
}
}
}else{
return this.formatJSON(500, "请先绑定手机号!", null);
}
}
}else{
return this.formatJSON(500, "登录状态已失效,请重新登录!", null);
}
} catch (WxPayException e) {
log.error("微信退款接口错误信息= {}", e);
return this.formatJSON(500, "微信退款接口出现异常!", null);
}
}
/**
* 仅支持一次性退款,多次退款需要修改逻辑
* @param xmlData 微信返回的流数据
* @return
*/
@RequestMapping(value = "refundNotify",method = {RequestMethod.GET,RequestMethod.POST})
public String refundNotify(@RequestBody String xmlData) {
WxPayRefundNotifyResult wxPayRefundNotifyResult;
try {
wxPayRefundNotifyResult = wxPayService.parseRefundNotifyResult(xmlData);
} catch (WxPayException e) {
log.error("退款失败,失败信息:{}", e);
return WxPayNotifyResponse.fail("退款失败");
}
//判断你返回状态信息是否正确
if (REFUND_SUCCESS.equals(wxPayRefundNotifyResult.getReturnCode())) {
WxPayRefundNotifyResult.ReqInfo reqInfo = wxPayRefundNotifyResult.getReqInfo();
//判断退款状态
if (REFUND_SUCCESS.equals(reqInfo.getRefundStatus())) {
//内部订单号
String outTradeNo = reqInfo.getOutTradeNo();
System.out.println("订单号:"+outTradeNo);
/**
* 一、可能会重复回调,需要做防重判断
* 二、处理我们系统内部业务,做修改订单状态,释放资源等!
*/
return WxPayNotifyResponse.success("退款成功!");
}
}
return WxPayNotifyResponse.fail("回调有误!");
}
/**
* 1 块钱转为 100 分
* 元转分
*
* @param bigDecimal 钱数目
* @return 分
*/
private int yuanToFee(BigDecimal bigDecimal) {
return bigDecimal.multiply(new BigDecimal(100)).intValue();
}
}