微信H5支付(MWEB)、掃碼支付(NATIVE)

1.下單回調方法

    @ResponseBody
    @ApiOperation("微信瀏支付/(H5)")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "productId", value = "產品ID",required=true),
            @ApiImplicitParam(name = "client", value = "下單客戶端:0=h5、1=pc",required=true),
            @ApiImplicitParam(name = "passagewayId", value = "支付通道ID",required=true)
    })
    @ApiResponses(value = {
            @ApiResponse(code = 500, message = "系統錯誤"),
            @ApiResponse(code = 200, message = "{code:響應碼,message:描述,data:參考model類{}}", response = BaseResult.class)})
    @GetMapping(value = "wxPayH5")
    public BaseResult wxPayH5(HttpServletRequest request,BeanOrder beanOrder) {
        Map<String, Object> result = new HashMap();
        result.put("success", false);
        try {

            Long userId = accessTokenService.getAppUserId(request);
            logger.info("1.發起微信瀏支付=========================================================》》productId="+ beanOrder.getProductId() + "=======》》 userId" + userId);
            // 價格 注意:價格的單位是分
            beanOrder.setAmount(new BigDecimal("1"));
            String order_price = beanOrder.getAmount().multiply(new BigDecimal(100)).toString().split("\\.")[0];
            beanOrder.setUserId(userId);
            // 下單客戶端:0=h5、1=pc (掃碼支付)
            beanOrder.setClient(1);

            if(EmptyUtil.isEmpty(beanOrder) || EmptyUtil.isEmpty(beanOrder.getAmount())
                    || EmptyUtil.isEmpty(beanOrder.getProductId())
                    || EmptyUtil.isEmpty(beanOrder.getUserId())
                    || EmptyUtil.isEmpty(beanOrder.getClient())
                    || EmptyUtil.isEmpty(beanOrder.getPassagewayId())){
                return new BaseResult(ResultEnum.ZC_120000.getCode(),"參數缺失",null);
            }

            logger.info("2.拼接統一下單地址參數===================================================》》\n ");
            Map<String, String> packageParams = AuthUtil.getPackageParams(request);
            packageParams.put("total_fee", "1");                              // 支付金額,單位分
            packageParams.put("detail", JSON.toJSONString(beanOrder));        // 商品詳情
            packageParams.put("notify_url", AuthUtil.NOTIFY_URL_H5 + "?productId="+beanOrder.getProductId()+"&userId="+userId); // 此路徑是微信服務器調用支付結果通知路徑隨意寫
            packageParams.put("trade_type", beanOrder.getClient() == 1 ? "NATIVE" : "MWEB");        // 支付類型
            String sign = WXPayUtil.generateSignature(packageParams, AuthUtil.PATERNERKEY);
            packageParams.put("sign", sign);                                //簽名
            String requestXML = WXPayUtil.mapToXml(packageParams);        // 將所有參數(map)轉xml格式

            logger.info("3.發送post請求統一下單接口返回預支付id:prepay_id  ======================》》\n" + requestXML);
            String resXml = HttpRequest.httpsRequest(AuthUtil.UFDODER_URL, "POST", requestXML);
            Map<String, String> map = WXPayUtil.xmlToMap(resXml);

            logger.info("4.響應參數 =============================================================》》\n" + resXml);
            String urlString = URLEncoder.encode("https://testm.tanxingk.com/kcoin/buy", "GBK");
            String url = beanOrder.getClient() == 1 ? map.get("code_url") : map.get("mweb_url");
            String retsult = url + "&redirect_url=" + urlString;

            logger.info("5.請求結束 =============================================================》》\n" + retsult);
            return new BaseResult(ResultEnum.QX_000000.getCode(),retsult);
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            return new BaseResult(ResultEnum.ZC_120000.getCode());
        }
    }

    @ResponseBody
    @ApiOperation("支付完成的回調函數")
    @ApiImplicitParams({
    })
    @ApiResponses(value = {
            @ApiResponse(code = 500, message = "系統錯誤"),
            @ApiResponse(code = 200, message = "{code:響應碼,message:描述,data:參考model類{}}", response = BeanOrder.class)})
    @RequestMapping("/payNotify")
    public void payNotify(HttpServletRequest request, HttpServletResponse response) {
        try {
            String xmlMsg = AuthUtil.readData(request);
            Map<String,String> params = WXPayUtil.xmlToMap(xmlMsg);
            logger.info("1.支付回調=========================================================》》" + xmlMsg);
            BeanOrder beanOrder = new BeanOrder();
            beanOrder.setUserId(Long.valueOf(params.get("userId")));
            beanOrder.setProductId(Long.valueOf(params.get("productId")));
            BeanProduct product = productService.findBeanProductId(beanOrder.getProductId());
            User user = userService.requiresNewSelectByPrimaryKey(beanOrder.getUserId());
            beanOrder.setAmount(product.getPrice());
            beanOrder.setOrderType(1);
            beanOrder.setMobile(user.getMobile());
            beanOrder.setPassagewayId(1);
            beanOrder.setCount(product.getNumber());
            try {
                Boolean czflg = true;
                logger.info("2.回調參數pay notice====================================================》》 \n"+params);
                String resXml = "";
                logger.info("3.處理業務開始========================================================》》\n");
                if ("SUCCESS".equals((String) params.get("result_code"))) {
                    logger.info("4.支付成功========================================================》》\n" + params);
                    try {
                        synchronized (czflg) {
                            // 1.訂單信息
                            beanOrder.setLogContent(params.toString());
                            beanOrder.setOrderNumber(params.get("nonce_str"));
                            BaseResult result = beanOrderService.addBeanOrder(beanOrder, user);
                            logger.info("5.支付結果========================================================》》\n" + result.toString());
                        }
                    } catch (Exception e) {
                        logger.error(e.getMessage(),e);
                    }
                    logger.info("6.通知微信.異步確認成功.必寫.不然會一直通知後臺.八次之後就認爲交易失敗了====》》\n");
                    resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                } else {
                    resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[充值失敗]]></return_msg>" + "</xml> ";
                }
                BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
                out.write(resXml.getBytes());
                out.flush();
                out.close();
            } catch (Exception e) {
                logger.error(e.getMessage(),e);
                throw new BusinessException("充值異常");
            }
        } catch (Exception e) {
            logger.error("充值異常",e);
        }
    }

2.訂單類

package com.fushui.business.kbeans.model;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import net.sf.jsqlparser.statement.select.First;
import org.hibernate.validator.constraints.Length;

import java.util.Date;
import java.math.BigDecimal;

/**
 * K豆訂單(bean_order)
 * 
 * @author Evan
 * @version 1.0.0 2020-02-25
 */
@ApiModel(description = "K豆訂單")
public class BeanOrder implements java.io.Serializable {
    /** 版本號 */
    private static final long serialVersionUID = -5339897937895258326L;

    @Length(max=10,message = "最大長度爲10",groups = {First.class})
    @ApiModelProperty(value = "")
    private Long orderId;

    @ApiModelProperty(value = "產品Id")
    private Long productId;

    @ApiModelProperty(value = "購買人id")
    private Long userId;

    @ApiModelProperty(value = "支付通道ID beans_passageway_set")
    private Integer passagewayId;

    @ApiModelProperty(value = "訂單類型ID order_type")
    private Integer orderType;

    @ApiModelProperty(value = "下單客戶端:0=h5、1=pc")
    private Integer client;

    @ApiModelProperty(value = "訂單類型名稱")
    private String orderTypeName;

    @ApiModelProperty(value = "聯繫方式")
    private String mobile;

    @ApiModelProperty(value = "商家訂單號")
    private String orderNumber;

    @ApiModelProperty(value = "返回日誌")
    private String logContent;

    @ApiModelProperty(value = "支付金額/元")
    private BigDecimal amount;

    @ApiModelProperty(value = "購買數量")
    private Integer count;

    @ApiModelProperty(value = "訂單狀態")
    private Integer status;

    @ApiModelProperty(value = "訂單狀態")
    private String statusName;

    @ApiModelProperty(value = "創建時間")
    private Date createTime;

    @ApiModelProperty(value = "通道名稱")
    private String passagewayName;

    @ApiModelProperty(value = "產品名稱")
    private String title;


}


3.工具類方法

package com.fushui.common.util.wxpay;

import com.alibaba.fastjson.JSON;
import com.github.wxpay.sdk.WXPayUtil;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;

/**
 * @ClassName AuthUtil
 * @Description TODO
 * @Author Evan
 * @Date 2020/3/18 16:18
 * @Version 1.0
 **/

public class AuthUtil {

    public static final String APPID = "******************";//平臺ID
    public static final String APPSECRET = "";              //平臺密鑰
    public static final String MCHID = "**********";        //商家ID
    public static final String PATERNERKEY = "****************";                      // 商家密鑰
    public static String NOTIFY_URL = "https://testm.tanxingk.com/api/wxpay/payNotify";      // 回調地址
    public static String NOTIFY_URL_H5 = "https://testm.tanxingk.com/api/wxpay/payNotify";   // 微信支付h5 回調地址
    public static String BODY = "彈性K線-K線資訊";                                                      // 商品名稱
    public static String UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";                // 請求地址
    public static String ORDERQUERY = "https://api.mch.weixin.qq.com/pay/orderquery";                   // 微信支付V2賬單查詢接口

    /**
     * @Author Evan
     * @Description //TODO 支付基本參數
     * @Date 14:43 2020/5/8
     * @Param [request]
     * @return java.util.Map<java.lang.String,java.lang.String>
     **/
    public static Map<String, String> getPackageParams(HttpServletRequest request){
        Map<String, String> packageParams = new TreeMap();
        String ip =  AuthUtil.getIp(request);
        packageParams.put("appid", AuthUtil.APPID);                     //  微信分配的公衆賬號ID(企業號corpid即爲此appId)
        packageParams.put("mch_id", AuthUtil.MCHID);                    // 微信支付分配的商戶號
        packageParams.put("body", AuthUtil.BODY);                       // 商品描述
        packageParams.put("nonce_str", WXPayUtil.generateNonceStr());   // 生成簽名的時候需要你自己設置隨機字符串
        packageParams.put("out_trade_no", UUID.randomUUID().toString().replaceAll("-", "")); // 商戶系統內部的訂單號,32個字符
        packageParams.put("spbill_create_ip",ip);                        // 必須傳正確的用戶端IP
        packageParams.put("scene_info", "{\"h5_info\": {\"type\":\"Wap\",\"wap_url\": \"https://testm.tanxingk.com/kcoin/buy\",\"wap_name\": \"彈性K線\"}}");
        return packageParams;
    }

    public static String readData(HttpServletRequest request) {
        BufferedReader br = null;
        try {
            StringBuilder result = new StringBuilder();
            br = request.getReader();
            for (String line; (line = br.readLine()) != null; ) {
                if (result.length() > 0) {
                    result.append("\n");
                }
                result.append(line);
            }
            return result.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (br != null)
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

    /**
     * 獲取用戶真實IP地址,不使用request.getRemoteAddr();的原因是有可能用戶使用了代理軟件方式避免真實IP地址。
     * 可是,如果通過了多級反向代理的話,X-Forwarded-For的值並不止一個,而是一串IP值,究竟哪個纔是真正的用戶端的真實IP呢?
     * 答案是取X-Forwarded-For中第一個非unknown的有效IP字符串
     * @param request
     * @return
     */
    public static String getIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
            if("127.0.0.1".equals(ip)||"0:0:0:0:0:0:0:1".equals(ip)){
                //根據網卡取本機配置的IP
                InetAddress inet=null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                ip= inet.getHostAddress();
            }
        }
        return ip;
    }

    public static String getInterfaceIp(HttpServletRequest request) {
        return getIp(request) + ":" + request.getServerPort();
    }
}

4.前端代碼

async clickSurePay() {
            if (this.choosePayId === '') {
                this.$showToast('請選擇支付方式');
            }
            console.log(this.choosePayId);
            console.log(this.chooseProductId);
            // this.$showToast('功能開發中,敬請期待!');
            const [_, resp] = await getAsync('/wxpay/wxPayH5', {
                productId: this.chooseProductId,
                passagewayId: this.choosePayId
            });
            console.log(resp);
            if (resp?.code === '000000') {
                const data = resp.data || {};
                // 調起微信支付
                console.log(data);
                location.href = data;
            } else {
            }
        };

 

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