Java實現微信支付

1、業務需求php

  實現app微信支付,後端須要作生成預支付單,響應支付結果。後端

2、業務流程api

  查看官方文檔服務器

  https://pay.weixin.qq.com/wik...微信

3、實現方法微信開發

  3.1 建立微信工具類 ConstantUtil
[Java] 純文本查看 複製代碼
?app

public class ConstantUtil {dom

/**
 * 微信開發平臺應用ID
 */
public static final String APP_ID="wx2421b1c4370ec43b";
/**
 * 應用對應的憑證
 */
public static final String APP_SECRET="1add1a30ac87aa2db72f57a2375d8fec";
/**
 * 應用對應的密鑰
 */
public static final String APP_KEY="1add1a30ac87aa2db72f57a2375d8fec";
/**
 * 微信支付商戶號
 */
public static final String MCH_ID="10000100";
/**
 * 商品描述
 */
public static final String BODY="充值";
/**
 * 商戶號對應的密鑰
 */
public static final String PARTNER_key="*******"; 

/**
 * 商戶id
 */
public static final String PARTNER_ID="*******"; 
/**
 * 常量固定值
 */
public static final String GRANT_TYPE="client_credential";
/**
 * 獲取預支付id的接口url
 */
public static String GATEURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
/**
 * 微信服務器回調通知url
 */
public static String NOTIFY_URL="http://url"; //能夠訪問的url
/**
 * 微信服務器查詢訂單url
 */
public static String ORDER_QUERY="https://api.mch.weixin.qq.com/pay/orderquery";

}異步

  3.2 生成預支付訂單
[Java] 純文本查看 複製代碼
?ide

Map<String, Object> getOrder(@RequestParam(value = "totalFee") String totalFee, @RequestParam(value = "deviceInfo") String deviceInfo,

@RequestParam(value = "attach") String attach,
                             HttpServletRequest request, HttpServletResponse response)
        throws Exception {
    Map<String, Object> map = new HashMap<String, Object>();
    // 獲取生成預支付訂單的請求類
    PrepayIdRequestHandler prepayReqHandler = new PrepayIdRequestHandler(request, response);

// String totalFee = request.getParameter("total_fee");

int total_fee = (int) (Float.valueOf(totalFee) * 100);
    System.out.println("total:" + total_fee);
    System.out.println("total_fee:" + total_fee);
    prepayReqHandler.setParameter("appid", ConstantUtil.APP_ID);
    prepayReqHandler.setParameter("body", ConstantUtil.BODY);
    prepayReqHandler.setParameter("mch_id", ConstantUtil.MCH_ID);
    prepayReqHandler.setParameter("device_info", deviceInfo); //卡號
    prepayReqHandler.setParameter("attach", attach);//套餐值
    String nonce_str = WXUtil.getNonceStr();
    prepayReqHandler.setParameter("nonce_str", nonce_str);
    prepayReqHandler.setParameter("notify_url", ConstantUtil.NOTIFY_URL);
    out_trade_no = String.valueOf(UUID.next());
    prepayReqHandler.setParameter("out_trade_no", out_trade_no);
    prepayReqHandler.setParameter("spbill_create_ip", request.getRemoteAddr());
    String timestamp = WXUtil.getTimeStamp();
    prepayReqHandler.setParameter("time_start", timestamp);
    System.out.println(String.valueOf(total_fee));
    prepayReqHandler.setParameter("total_fee", String.valueOf(total_fee));
    prepayReqHandler.setParameter("trade_type", "APP");
    /**
     * 注意簽名(sign)的生成方式,具體見官方文檔(傳參都要參與生成簽名,且參數名按照字典序排序,最後接上APP_KEY,轉化成大寫)
     */
    prepayReqHandler.setParameter("sign", prepayReqHandler.createMD5Sign());
    prepayReqHandler.setGateUrl(ConstantUtil.GATEURL);
    String prepayid = prepayReqHandler.sendPrepay();
    // 若獲取prepayid成功,將相關信息返回客戶端
    if (prepayid != null && !prepayid.equals("")) {
        String signs = "appid=" + ConstantUtil.APP_ID + "&noncestr=" + nonce_str + "&package=Sign=WXPay&partnerid="
                + ConstantUtil.PARTNER_ID + "&prepayid=" + prepayid + "×tamp=" + timestamp + "&key="
                + ConstantUtil.APP_KEY;
        map.put("code", 0);
        map.put("info", "success");
        map.put("prepayid", prepayid);
        /**
         * 簽名方式與上面相似
         */
        map.put("sign", MD5Util.MD5Encode(signs, "utf8").toUpperCase());
        map.put("appid", ConstantUtil.APP_ID);
        map.put("device_info", deviceInfo);
        map.put("attach", attach);
        map.put("timestamp", timestamp);  //等於請求prepayId時的time_start
        map.put("noncestr", nonce_str);   //與請求prepayId時值一致
        map.put("package", "Sign=WXPay");  //固定常量
        map.put("partnerid", ConstantUtil.PARTNER_ID);
    } else {
        map.put("code", 1);
        map.put("info", "獲取prepayid失敗");
    }
    return map;
}

  3.3 異步通知客戶結果

[Java] 純文本查看 複製代碼
?

PrintWriter writer = response.getWriter();

InputStream inStream = request.getInputStream();
    ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int len = 0;
    while ((len = inStream.read(buffer)) != -1) {
        outSteam.write(buffer, 0, len);
    }
    outSteam.close();
    inStream.close();
    String result = new String(outSteam.toByteArray(), "utf-8");
    System.out.println("微信支付通知結果:" + result);
    Map<String, String> map = null;
    try {
        /**
         * 解析微信通知返回的信息
         */
        map = XMLUtil.doXMLParse(result);
    } catch (JDOMException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

   官方文檔中特別提醒:商戶系統對於支付結果通知的內容必定要作簽名驗證,並校驗返回的訂單金額是否與商戶側的訂單金額一致,防止數據泄漏致使出現「假通知」,形成資金損失。
   支付結果通知內容作簽名驗證。

[Java] 純文本查看 複製代碼

//支付成功後sign校驗
String appid=map.get("appid");
String transaction_id=map.get("transaction_id");
String nonce_str =map.get("nonce_str");
String bank_type =map.get("bank_type");
String openid=map.get("openid");
String sign =map.get("sign");
String fee_type =map.get("fee_type");
String mch_id =map.get("mch_id");
String cash_fee =map.get("cash_fee");
String device_info =map.get("device_info");
String out_trade_no =map.get("out_trade_no");
String total_fee =map.get("total_fee");
String trade_type =map.get("trade_type");
String result_code =map.get("result_code");
String attach =map.get("attach");
String time_end =map.get("time_end");
String is_subscribe =map.get("is_subscribe");
String return_code=map.get("return_code");

PrepayIdRequestHandler prepayReqHandler = new PrepayIdRequestHandler(request, response);
prepayReqHandler.setParameter("appid",appid);
prepayReqHandler.setParameter("attach",attach);
prepayReqHandler.setParameter("bank_type",bank_type);
prepayReqHandler.setParameter("cash_fee",cash_fee);
prepayReqHandler.setParameter("device_info",device_info);
prepayReqHandler.setParameter("fee_type",fee_type);
prepayReqHandler.setParameter("is_subscribe",is_subscribe);
prepayReqHandler.setParameter("mch_id",mch_id);
prepayReqHandler.setParameter("nonce_str",nonce_str);
prepayReqHandler.setParameter("openid",openid);
prepayReqHandler.setParameter("out_trade_no",out_trade_no);
prepayReqHandler.setParameter("result_code",result_code);
prepayReqHandler.setParameter("return_code",return_code);
prepayReqHandler.setParameter("time_end",time_end);
prepayReqHandler.setParameter("total_fee",total_fee);
prepayReqHandler.setParameter("trade_type",trade_type);
prepayReqHandler.setParameter("transaction_id",transaction_id);

String endSigns =prepayReqHandler.createMD5Sign(); //支付結果通知的內容 簽名校驗

  商戶金額的查詢

[Java] 純文本查看 複製代碼
?

PrepayIdRequestHandler orderQueryHandler = new PrepayIdRequestHandler(request, response);

orderQueryHandler.setParameter("appid",appid);
    orderQueryHandler.setParameter("mch_id",mch_id);
    orderQueryHandler.setParameter("out_trade_no",out_trade_no);
    orderQueryHandler.setParameter("nonce_str",nonce_str);
    orderQueryHandler.setParameter("sign",orderQueryHandler.createMD5Sign());
    orderQueryHandler.setGateUrl(ConstantUtil.ORDER_QUERY);
    String resXml = "";
    WeixinOrderBean orderBean =orderQueryHandler.selectOrder();

  應答微信 

[AppleScript] 純文本查看 複製代碼

if(sign.equals(endSigns) && Integer.parseInt(total_fee)==orderBean.getTotal_fee()){ // 簽名經過而且返回的訂單的金額與商戶金額相同

// 若支付成功,則告知微信服務器收到通知
        if (map.get("return_code").equals("SUCCESS")) {
            System.out.println("充值成功!");
            //PayRecord payRecord=payRecordService.get(Long.valueOf(map.get("out_trade_no")));
            System.out.println("訂單號:" + Long.valueOf(map.get("out_trade_no")));
            String iccids = map.get("device_info");
            String monthNum = map.get("attach");

          //根據本身的業務處理

int count =trafficCardListService.selectExistTrafficCardByOutTradeNo(map.get("out_trade_no")); //查詢商戶訂單號是否存在
            if(count==0){//不存在就插入
                List<MsisdnOrderBean> msisdnOrderList = trafficCardListService.selectTrafficCardRechargeResult(iccids, monthNum);
                if (msisdnOrderList.size() > 0) {
                    for (MsisdnOrderBean msisdnOrderBean : msisdnOrderList) {
                        msisdnOrderBean.setOutTradeNo(map.get("out_trade_no"));
                        msisdnOrderBean.setDate(map.get("time_end"));
                        msisdnOrderBean.setIccids(map.get("device_info"));
                        // msisdnOrderBean.setTotalFee(Integer.parseInt(map.get("total_fee")));
                        msisdnOrderBean.setTotalFee(BigDecimal.valueOf(Integer.parseInt(map.get("total_fee"))).divide(new BigDecimal(100)).doubleValue());
                        msisdnOrderBean.setTransactionId(map.get("transaction_id"));
                        msisdnOrderBean.setTrafficNo(DateUtils.getNowDataTime() + ApiUtils.getFourRandom()); //年月日時分秒+四位隨機數
                        trafficCardListService.insertTrafficCardList(msisdnOrderBean);
                    }
                }
            }
            resXml = XMLUtil.setXML("SUCCESS", "OK");
        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[通知簽名驗證失敗]]></return_msg>" + "</xml> ";
            logger.info("通知簽名驗證失敗");
        }
    }else{
        resXml =XMLUtil.setXML("FAIL", "簽名不一致");
    }

    writer.write(resXml);
    writer.flush();
    writer.close();

  運用到的 PrepayIdRequestHandler 工具類

[Java] 純文本查看 複製代碼

public class PrepayIdRequestHandler extends RequestHandler {

public PrepayIdRequestHandler(HttpServletRequest request,
                              HttpServletResponse response) {
    super(request, response);
}

public String createMD5Sign() {
    StringBuffer sb = new StringBuffer();
    Set es = super.getAllParameters().entrySet();
    Iterator it = es.iterator();
    while (it.hasNext()) {
        Map.Entry entry = (Map.Entry) it.next();
        String k = (String) entry.getKey();
        String v = (String) entry.getValue();
        sb.append(k + "=" + v + "&");
    }

    String params=sb.append("key="+ConstantUtil.APP_KEY).substring(0);
    String sign = MD5Util.MD5Encode(params, "utf8");
    return sign.toUpperCase();
}

// 提交預支付
public String sendPrepay() throws Exception {
    String prepayid = "";
相關文章
相關標籤/搜索