小程式專案微信支付
阿新 • • 發佈:2021-12-08
微信支付
去年開發的小程式支付專案,一直沒空梳理
需要申請商家支付服務
檢視開發文件流程
流程:
->使用者在購物車頁點選支付
-> 這時調起我們寫的介面(使用者所攜帶的商品id,金額等等引數攜帶到伺服器)
-> 這時業務操作可以在這裡實現,比如生成訂單 -> 商戶後臺收到使用者支付單,(需要填上支付成功回撥介面)呼叫微信支付統一下單介面
-> 傳送post請求"統一下單介面"返回預支付id:prepay_id (需要把參與簽名的欄位名為appid,partnerid,prepayid,noncestr,timestamp,package 返回給前端 然後喚起支付頁面)
-> 前端支付成功後會走支付回撥介面
使用Java開發微信支付
demo工具類下載
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
開發介面如下
@Slf4j @Api(tags = "app支付功能") @RestController @RequestMapping("/payment/") public class PaymentController { @Resource private Environment environment; /*呼叫支付介面*/ @ApiOperation(httpMethod = "POST", value = "呼叫支付介面") @RequestMapping(value = "prePay", method = RequestMethod.POST) public Map<String, Object> prePay(@RequestBody Pay pay,HttpServletRequest request){ log.info("呼叫支付介面"); // 返回引數 Map<String, Object> resMap = new HashMap<>(); //獲取當前請求ip地址 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.getRemoteAddr(); } if(ip.indexOf(",")!=-1){ String[] ips = ip.split(","); ip = ips[0].trim(); } try { //業務需求 //前臺傳輸一個openid--每個使用者對應小程式都會生成一個獨一無二的openid Map<String, Object> paraMap = new HashMap<>(); //查詢房屋 String body = "cs"; // 封裝11個必需的引數 //小程式ID paraMap.put("appid", environment.getProperty("wx.appId")); //商家ID paraMap.put("mch_id", environment.getProperty("wx.mchId")); //獲取隨機字串 Nonce Str paraMap.put("nonce_str", WXPayUtil.generateNonceStr()); //商品名稱 paraMap.put("body", body); //訂單號 if (pay.getType()==MsgConsts.ZERO_STATUS) { //業務需求 // DecimalFormat df = new DecimalFormat("0.00%"); NumberFormat numberFormat = NumberFormat.getPercentInstance(); Double money = hpOrder.getTotalFee();//租金 numberFormat.setMinimumFractionDigits(2);//保留到小數點後2位,不設定或者設定為0表示不保留小數 //支付金額,單位:分,這邊需要轉成字串型別,否則後面的簽名會失敗 String totalFee= BigDecimal.valueOf(money).multiply(new BigDecimal(100)).setScale(0,BigDecimal.ROUND_HALF_UP) + ""; paraMap.put("total_fee",totalFee); paraMap.put("out_trade_no", hpOrder.getOrderNo()); }else{ Double money = obOrder.getTotalFee(); //支付金額,單位:分,這邊需要轉成字串型別,否則後面的簽名會失敗 String totalFee= BigDecimal.valueOf(money).multiply(new BigDecimal(100)).setScale(0,BigDecimal.ROUND_HALF_UP) + ""; paraMap.put("total_fee",totalFee); paraMap.put("out_trade_no", obOrder.getOrderNo()); } paraMap.put("spbill_create_ip", ip); // 此路徑是微信伺服器呼叫支付結果通知路徑 paraMap.put("notify_url", "http://payment/callBack"); paraMap.put("trade_type", "JSAPI"); paraMap.put("openid", pay.getOpenid()); String sign = WXPayUtil.generateSignature(paraMap, environment.getProperty("wx.mchKey")); //生成簽名. 注意,若含有sign_type欄位,必須和signType引數保持一致。 paraMap.put("sign", sign); //將所有引數(map)轉xml格式 String xml = WXPayUtil.mapToXml(paraMap); log.info("xml=: "+xml); // 統一下單 https://api.mch.weixin.qq.com/pay/unifiedorder String unifiedorder_url = WXPayConstants.UNIFIEDORDER_URL; log.info("統一下單介面unifiedorder_url:"+unifiedorder_url); //傳送post請求"統一下單介面"返回預支付id:prepay_id String xmlStr = HttpClientUtil.doPostXml(unifiedorder_url, xml); //以下內容是返回前端頁面的json資料 //預支付id String prepay_id = ""; if (xmlStr.indexOf("SUCCESS") != -1) { Map<String, Object> map = WXPayUtil.xmlToMap(xmlStr);//XML格式字串轉換為Map //獲取封裝好的預支付id prepay_id = map.get("prepay_id").toString(); log.info("prepay_id_1= "+prepay_id); } // 封裝所需6個引數調支付頁面 Map<String, Object> payMap = new HashMap<String, Object>(); payMap.put("appId", environment.getProperty("wx.appId")); payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp()+"");//獲取當前時間戳,單位秒 payMap.put("nonceStr", WXPayUtil.generateNonceStr());//獲取隨機字串 Nonce Str payMap.put("signType", "MD5"); payMap.put("package", "prepay_id=" + prepay_id); //生成帶有 sign 的 XML 格式字串 String paySign = WXPayUtil.generateSignature(payMap, environment.getProperty("wx.mchKey")); payMap.put("paySign", paySign); // 封裝正常情況返回資料 resMap.put("success",true); resMap.put("payMap",payMap); } catch (Exception e) { //異常刪除訂單 // 封裝異常情況返回資料 log.info("呼叫統一訂單介面錯誤"); resMap.put("success",false); resMap.put("message","呼叫統一訂單介面錯誤"); e.printStackTrace(); } return resMap; } /*支付成功回撥*/ @ApiOperation(httpMethod = "POST", value = "呼叫支付成功回撥的地址") @RequestMapping(value = "callBack") public Result callBack(HttpServletRequest request, HttpServletResponse response){ Result result = new Result(); log.info("呼叫微信支付成功回撥"); InputStream is = null; String resXml = ""; try { is = request.getInputStream();//獲取請求的流資訊(這裡是微信發的xml格式所有隻能使用流來讀) String xml = WXPayUtil.inputStream2String(is); Map<String, Object> notifyMap = WXPayUtil.xmlToMap(xml);//將微信發的xml轉map if(notifyMap.get("return_code").equals("SUCCESS")){ try { //業務需求 resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream()); out.write(resXml.getBytes()); out.flush(); out.close(); System.err.println("返回給微信的值:"+resXml.getBytes()); is.close(); }catch (Exception e){ log.info("訂單狀態修改失敗"); result.setMsg("訂單狀態修改失敗"); } } } catch (Exception e) { e.printStackTrace(); } return result; } }
支付引數
@Data public class Pay { public String openid; private Long id; private Long customerViewingRecordId; private Long userId; private Integer type; private String ordersNo; private String frontIdCardUrl; private String backIdCardUrl; private String contractUrl; private String idCard; private String contactName; private String phoneNumber; }