weixin-java-pay實現公衆號微信支付與退款

內容來自:https://www.jianshu.com/p/0a0ccc15cb80

pom.xml 文件
需要在 pom.xml 加入以下依賴!

    <dependency>
        <groupId>com.github.binarywang</groupId>
        <artifactId>weixin-java-pay</artifactId>
        <version>3.0.0</version>
    </dependency>

application.yml 文件
將 application.yml 中修改自己商戶平臺的信息,以下 keyPath 是證書,可以在微信支付後臺下載,指定相關目錄即可。

wx:
  pay:
    appId: #微信公衆號或者小程序等的appid
    mchId: #微信支付商戶號
    mchKey: #微信支付商戶密鑰
    keyPath: # p12證書的位置,可以指定絕對路徑,也可以指定類路徑(以classpath:開頭)
    tradeType: JSAPI  #JSAPI--公衆號支付    NATIVE--原生掃碼支付   APP--app支付  

假設我們將證書放到 resources 目錄下,那寫成以下形式即可。

keyPath: classpath:證書名

還需要準備兩個配置文件

WechatPayConfig 文件

import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

/**
 * @author Gentle
 * @date 2019/05/05
 * 微信支付信息注入bean 中
 */
@Component
public class WeChatPayConfig {
    @Autowired
    private WeChatPayProperties properties;

    @Bean
    @ConditionalOnMissingBean
    public WxPayConfig payConfig() {
        WxPayConfig payConfig = new WxPayConfig();
        payConfig.setAppId(this.properties.getAppId());
        payConfig.setMchId(this.properties.getMchId());
        payConfig.setMchKey(this.properties.getMchKey());
        payConfig.setKeyPath(this.properties.getKeyPath());
        payConfig.setTradeType(this.properties.getTradeType());
        payConfig.setNotifyUrl(this.properties.getNotifyUrl());
        return payConfig;
    }
    @Bean
    public WxPayService wxPayService(WxPayConfig payConfig) {
        WxPayService wxPayService = new WxPayServiceImpl();
        wxPayService.setConfig(payConfig);
        return wxPayService;
    }
}

微信支付接口的 Controller

import com.gentle.config.WeChatPayProperties;
import com.gentle.entity.ReturnPayInfoVO;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;

/**
 * @author : Gentle
 * @date : 2019/5/17 12:11
 * @description:
 */
@RestController
@RequestMapping(value = "/api/client/pay/")
public class WeChatPayController {

    @Autowired
    private WxPayService wxPayService;
    @Autowired
    WeChatPayProperties weChatPayProperties;

    /**
     * 此處處理訂單信息,構建訂單數據。
     *
     * 將構建好的支付參數返回到前端,前端調起微信支付
     * @return
     */
    @GetMapping(value = "weChatPay")
    public ReturnPayInfoVO weChatPay() {
        /**
         * 處理內部業務,校驗訂單等
         */
        final WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = WxPayUnifiedOrderRequest.newBuilder()
                //調起支付的人的 openId
                .openid("openId")
                //訂單編號
                .outTradeNo("我們系統內部訂單號")
                //訂單金額
                .totalFee(yuanToFee(new BigDecimal(100)))
                //商品描述
                .body("訂單信息")
                //獲取本地IP
                .spbillCreateIp(InetAddress.getLoopbackAddress().getHostAddress())
                //回調的 URL 地址
                .notifyUrl("http://我們的域名/api/client/pay/weChatPayNotify")
                .build();
        WxPayUnifiedOrderResult wxPayUnifiedOrderResult =null;
        try {
            wxPayUnifiedOrderResult = wxPayService.unifiedOrder(wxPayUnifiedOrderRequest);
        } catch (WxPayException e) {
            e.printStackTrace();
            throw new RuntimeException("微信支付調起失敗!");
        }
        //組合參數構建支付
        Map<String, String> paySignInfo = new HashMap<>(5);
        String timeStamp = createTimestamp();
        String nonceStr = String.valueOf(System.currentTimeMillis());
        paySignInfo.put("appId", weChatPayProperties.getAppId());
        paySignInfo.put("nonceStr", nonceStr);
        paySignInfo.put("timeStamp", timeStamp);
        paySignInfo.put("signType", "MD5");
        paySignInfo.put("package", "prepay_id=" + wxPayUnifiedOrderResult.getPrepayId());
        String paySign = SignUtils.createSign(paySignInfo, "MD5", weChatPayProperties.getMchKey(), false);

        //組合支付參數
        ReturnPayInfoVO returnPayInfoVO = new ReturnPayInfoVO();
        returnPayInfoVO.setAppId(weChatPayProperties.getAppId());
        returnPayInfoVO.setNonceStr(nonceStr);
        returnPayInfoVO.setPaySign(paySign);
        returnPayInfoVO.setSignType("MD5");
        returnPayInfoVO.setPrepayId(wxPayUnifiedOrderResult.getPrepayId());
        returnPayInfoVO.setTimeStamp(timeStamp);

        return returnPayInfoVO;
    }

    /**
     *
     * @param xmlData 微信返回的流
     * @return
     */
    @RequestMapping(value = "weChatPayNotify",method = {RequestMethod.GET,RequestMethod.POST})
    public String weChatNotify(@RequestBody String xmlData){

        try {
            final WxPayOrderNotifyResult notifyResult = this.wxPayService.parseOrderNotifyResult(xmlData);
            //這裏是存儲我們發起支付時訂單號的信息,所以取出來
            notifyResult.getOutTradeNo();
            /**
             * 系統內部業務,修改訂單狀態之類的
             */
            //成功後回調微信信息
            return WxPayNotifyResponse.success("回調成功!");
        } catch (WxPayException e) {
            e.printStackTrace();
            return WxPayNotifyResponse.fail("回調有誤!");
        }
    }
    /**
     * 1 塊錢轉爲 100 分
     * 元轉分
     *
     * @param bigDecimal 錢數目
     * @return 分
     */
    private int yuanToFee(BigDecimal bigDecimal) {
        return bigDecimal.multiply(new BigDecimal(100)).intValue();
    }
    /**
     * 時間
     *
     * @return 時間戳
     */
    private String createTimestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }
}

上述代碼便是位置支付的調起信息和支付成功後回調的處理邏輯了,可以對代碼進行適當的修改,便可使用。

微信退款實現:
以下便是微信退款的實現,代碼也相對簡單,修改以下便可使用,當然要各種參數校驗等,否則可能會出現被人惡意調起的可能!

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 lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;

/**
 * @author : Gentle
 * @date : 2019/5/17 12:38
 * @description:
 */
@RestController
@RequestMapping(value = "/api/client/refund/")
@Slf4j
public class WeChatRefundController {

    private static final String REFUND_SUCCESS = "SUCCESS";

    @Autowired
    private WxPayService wxPayService;

    @PostMapping(value = "weChatRefund")
    public String refund() {
        //申請退款
        WxPayRefundRequest refundInfo = WxPayRefundRequest.newBuilder()
                //訂單號
                .outTradeNo("自己系統訂單號")
                //退款訂單號
                .outRefundNo("自己系統訂單號")
                //金額
                .totalFee(yuanToFee(new BigDecimal(100)))
                //退款金額
                .refundFee(yuanToFee(new BigDecimal(100)))
                //todo 回調地址
                .notifyUrl("http://我們系統的域名/api/client/refund/refundNotify")
                .build();
        WxPayRefundResult wxPayRefundResult;
        try {
            wxPayRefundResult = wxPayService.refund(refundInfo);
            //判斷退款信息是否正確
            if (REFUND_SUCCESS.equals(wxPayRefundResult.getReturnCode())
                    && REFUND_SUCCESS.equals(wxPayRefundResult.getResultCode())) {
                /**
                 * 系統內部業務邏輯
                 */
                return "正在退款中。。";
            }
        } catch (WxPayException e) {
            log.error("微信退款接口錯誤信息= {}", e);
        }

        return "退款失敗";
    }


    /**
     * 僅支持一次性退款,多次退款需要修改邏輯
     * @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();
                /**
                 * 一、可能會重複回調,需要做防重判斷
                 * 二、處理我們系統內部業務,做修改訂單狀態,釋放資源等!
                 */
                return WxPayNotifyResponse.success("退款成功!");
            }
        }
        return WxPayNotifyResponse.fail("回調有誤!");
    }
    /**
     * 1 塊錢轉爲 100 分
     * 元轉分
     *
     * @param bigDecimal 錢數目
     * @return 分
     */
    private int yuanToFee(BigDecimal bigDecimal) {
        return bigDecimal.multiply(new BigDecimal(100)).intValue();
    }
    /**
     * 時間
     *
     * @return 時間戳
     */
    private String createTimestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }
}

案例相關代碼已經發布到 GitHub 和碼雲上,如有興趣可以下載學習!
GitHub:
https://github.com/LuckyToMeet-Dian-N/WeChat-Demo/tree/master/wechat-pay-demo
碼雲:
https://gitee.com/reway_wen/WeChat-Demo/tree/master/wechat-pay-demo

總結:
上述便是微信支付和微信退款的實現!代碼不難,只是開發資質倒是個問題。如果有資質的話,那這篇文章可能給到您一些幫助。



作者:LuckToMeetDian葉
鏈接:https://www.jianshu.com/p/0a0ccc15cb80
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章