您好,登錄后才能下訂單哦!
工作需要,寫了服務(wù)器端的支付和退款功能,包含微信和支付寶,網(wǎng)上也有很多demo可以借鑒,我把我的代碼放出來(lái),寫的比較簡(jiǎn)單,有問(wèn)題的歡迎指正,大家一起學(xué)習(xí)。
微信支付需要調(diào)用微信的統(tǒng)一下單接口,而支付寶不用。
我寫的時(shí)候微信和支付寶都單獨(dú)寫了一個(gè)工具類,來(lái)調(diào)用支付,給前端返回需要的數(shù)據(jù)。
ps:支付是可以不需要服務(wù)器端的,不過(guò)為了安全一點(diǎn)點(diǎn),所以前端需要調(diào)起支付的字段都直接從服務(wù)器端返回,前端拿到字段直接調(diào)起支付就可以了。
Map<String,String> map = new HashMap<String,String>(); switch (record.getCheckType()) { case 10: map = Alipay.prePay(record.getAmount(),out_trade_no); return ResponseData.ok(map); case 20: map = WXPay.prePay(record.getAmount(),out_trade_no); return ResponseData.ok(map); }
10是支付寶支付,20是微信支付,map里存放前端需要的字段,直接返回給手機(jī)端
其中out_trade_no這個(gè)是商戶自己生成的唯一訂單號(hào)
public class WXPay { private static String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder"); //統(tǒng)一下單 public static Map<String,String> prePay(BigDecimal amount,String out_trade_no){ String entity = genProductArgs(amount,out_trade_no); byte[] buf = Util.httpPost(url, entity); String content = new String(buf); Map<String,String> xml=decodeXml(content); return getRep(xml); } private static Map<String, String> getRep(Map<String, String> xml) { Random random = new Random(); List<NameValuePair> signParams = new LinkedList<NameValuePair>(); signParams.add(new BasicNameValuePair("appid", Constants.APP_ID_WX)); signParams.add(new BasicNameValuePair("noncestr", MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes()))); // signParams.add(new BasicNameValuePair("package", "prepay_id="+xml.get("prepay_id"))); signParams.add(new BasicNameValuePair("package", "Sign=WXPay")); signParams.add(new BasicNameValuePair("partnerid", Constants.MCH_ID)); signParams.add(new BasicNameValuePair("prepayid", xml.get("prepay_id"))); signParams.add(new BasicNameValuePair("timestamp", String.valueOf(System.currentTimeMillis() / 1000))); xml.put("sign", genPackageSign(signParams)); for (int i = 0; i < signParams.size(); i++) { xml.put(signParams.get(i).getName(),signParams.get(i).getValue()); } return removeElements(xml); } private static Map<String, String> removeElements(Map<String, String> xml) { xml.remove("appid"); xml.remove("mch_id"); xml.remove("nonce_str"); xml.remove("trade_type"); //xml.remove("partnerid"); xml.remove("prepay_id"); xml.remove("result_code"); xml.remove("return_code"); xml.remove("return_msg"); return xml; } private static String genProductArgs(BigDecimal amount,String out_trade_no) { StringBuffer xml = new StringBuffer(); String nonceStr = genNonceStr(); xml.append("</xml>"); List<NameValuePair> packageParams = new LinkedList<NameValuePair>(); packageParams.add(new BasicNameValuePair("appid", Constants.APP_ID_WX)); packageParams.add(new BasicNameValuePair("body", "APP pay test")); packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID)); packageParams.add(new BasicNameValuePair("nonce_str", nonceStr)); packageParams.add(new BasicNameValuePair("notify_url", "填寫服務(wù)器的支付回調(diào)路徑")); packageParams.add(new BasicNameValuePair("out_trade_no",out_trade_no)); packageParams.add(new BasicNameValuePair("spbill_create_ip","127.0.0.1")); packageParams.add(new BasicNameValuePair("total_fee", String.valueOf(amount.movePointRight(2)))); // packageParams.add(new BasicNameValuePair("total_fee", "1")); packageParams.add(new BasicNameValuePair("trade_type", "APP")); String sign = genPackageSign(packageParams); packageParams.add(new BasicNameValuePair("sign", sign)); String xmlstring =toXml(packageParams); return xmlstring; } public static String genNonceStr() { Random random = new Random(); return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes()); } public static String genPackageSign(List<NameValuePair> params) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < params.size(); i++) { sb.append(params.get(i).getName()); sb.append('='); sb.append(params.get(i).getValue()); sb.append('&'); } sb.append("key="); sb.append(Constants.API_KEY); String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase(); return packageSign; } public static String toXml(List<NameValuePair> params) { StringBuilder sb = new StringBuilder(); sb.append("<xml>"); for (int i = 0; i < params.size(); i++) { sb.append("<"+params.get(i).getName()+">"); sb.append(params.get(i).getValue()); sb.append("</"+params.get(i).getName()+">"); } sb.append("</xml>"); return sb.toString(); } }
public class Alipay { public static Map<String,String> prePay(BigDecimal payAbleAmount,String out_trade_no){ //String orderInfo = getOrderInfo("訂單付款", "訂單付款",out_trade_no,"0.01"); String orderInfo = getOrderInfo("訂單付款", "訂單付款",out_trade_no,String.valueOf(payAbleAmount)); String sign = sign(orderInfo); try { /** * 僅需對(duì)sign 做URL編碼 */ sign = URLEncoder.encode(sign, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } /** * 完整的符合支付寶參數(shù)規(guī)范的訂單信息 */ final String payInfo = orderInfo + "&sign=\"" + sign + "\"&" + getSignType(); Map<String,String> map = new HashMap<String, String>(); map.put("payInfo", payInfo); return map; } private static String getOrderInfo(String subject, String body,String out_trade_no,String price) { // 簽約合作者身份ID String orderInfo = "partner=" + "\"" + Constants.PARTNER + "\""; // 簽約賣家支付寶賬號(hào) orderInfo += "&seller_id=" + "\"" + Constants.SELLER + "\""; // 商戶網(wǎng)站唯一訂單號(hào) orderInfo += "&out_trade_no=" + "\"" + out_trade_no + "\""; // 商品名稱 orderInfo += "&subject=" + "\"" + subject + "\""; // 商品詳情 orderInfo += "&body=" + "\"" + body + "\""; // 商品金額 orderInfo += "&total_fee=" + "\"" + price + "\""; // 服務(wù)器異步通知頁(yè)面路徑 orderInfo += "¬ify_url=" + "\"" + "填寫服務(wù)器的支付回調(diào)路徑" + "\""; // 服務(wù)接口名稱, 固定值 orderInfo += "&service=\"mobile.securitypay.pay\""; // 支付類型, 固定值 orderInfo += "&payment_type=\"1\""; // 參數(shù)編碼, 固定值 orderInfo += "&_input_charset=\"utf-8\""; // 設(shè)置未付款交易的超時(shí)時(shí)間 // 默認(rèn)30分鐘,一旦超時(shí),該筆交易就會(huì)自動(dòng)被關(guān)閉。 // 取值范圍:1m~15d。 // m-分鐘,h-小時(shí),d-天,1c-當(dāng)天(無(wú)論交易何時(shí)創(chuàng)建,都在0點(diǎn)關(guān)閉)。 // 該參數(shù)數(shù)值不接受小數(shù)點(diǎn),如1.5h,可轉(zhuǎn)換為90m。 orderInfo += "&it_b_pay=\"30m\""; // extern_token為經(jīng)過(guò)快登授權(quán)獲取到的alipay_open_id,帶上此參數(shù)用戶將使用授權(quán)的賬戶進(jìn)行支付 // orderInfo += "&extern_token=" + "\"" + extern_token + "\""; // 支付寶處理完請(qǐng)求后,當(dāng)前頁(yè)面跳轉(zhuǎn)到商戶指定頁(yè)面的路徑,可空 orderInfo += "&return_url=\"m.alipay.com\""; // 調(diào)用銀行卡支付,需配置此參數(shù),參與簽名, 固定值 (需要簽約《無(wú)線銀行卡快捷支付》才能使用) // orderInfo += "&paymethod=\"expressGateway\""; return orderInfo; } private static String sign(String content) { return SignUtils.sign(content, Constants.RSA_PRIVATE); } private static String getSignType() { return "sign_type=\"RSA\""; } }
退款部分
支付寶
String strResponse = null; AlipayTradeRefundResponse response = null; try { AlipayClient alipayClient = new DefaultAlipayClient(url,Constants.APPID_ALIPAY,Constants.RSA_PRIVATE,"json","utf-8",Constants.RSA_PUBLIC); AlipayTradeRefundRequest request = new AlipayTradeRefundRequest(); RefundInfo alidata = new RefundInfo(); alidata.setOut_trade_no(out_trade_no); alidata.setRefund_amount(refund_amount); request.setBizContent(JSON.toJSONString(alidata)); response = alipayClient.sdkExecute(request); if (response.isSuccess()) { strResponse="退款成功"; } else { strResponse="退款失敗"; } return strResponse; } catch (Exception e) { strResponse="退款出錯(cuò)"; } return strResponse;
微信
public class WXRefund { private static final String url = "https://api.mch.weixin.qq.com/secapi/pay/refund"; /** * 微信退款 * @param out_trade_no 商戶訂單號(hào) * @param total_fee 總金額 * @param refund_fee 退款金額 * @return */ public static String doRefund(String out_trade_no,int total_fee,int refund_fee) { InputStream instream = null; KeyStore keyStore = null; CloseableHttpResponse response = null; CloseableHttpClient httpclient = null; StringBuilder text = new StringBuilder(); String key = Constants.MCH_ID; try { /** * 注意PKCS12證書 是從微信商戶平臺(tái)-》賬戶設(shè)置-》 API安全 中下載的 */ keyStore = KeyStore.getInstance("PKCS12"); instream = WXRefund.class.getResourceAsStream("/apiclient_cert.p12");//P12文件 /** * 此處要改 */ keyStore.load(instream, key.toCharArray());// 這里寫密碼..默認(rèn)是MCHID /** * 此處要改 */ SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, key.toCharArray())// 這里也是寫密碼的 .build(); // Allow TLSv1 protocol only SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); //=======================證書配置完成======================== HttpPost httpPost = new HttpPost(url); String xmlstring = getRefunArgs(out_trade_no,total_fee,refund_fee); httpPost.setEntity(new StringEntity(xmlstring)); httpPost.setHeader("Accept", "application/json"); httpPost.setHeader("Content-type", "application/json"); response = httpclient.execute(httpPost); HttpEntity entity = response.getEntity(); if (entity != null) { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent())); String str; while ((str = bufferedReader.readLine()) != null) { text.append(str); } } EntityUtils.consume(entity); }catch(Exception e){ }finally { if(instream != null){ try { instream.close(); } catch (IOException e) { e.printStackTrace(); } } if(response != null){ try { response.close(); } catch (IOException e) { e.printStackTrace(); } } if(httpclient != null){ try { httpclient.close(); } catch (IOException e) { e.printStackTrace(); } } } Map<String,String> map = WXPay.decodeXml(text.toString()); String return_msg = map.get("return_msg"); if ("OK".equals(return_msg) && "SUCCESS".equals(map.get("return_code"))) { return "退款成功"; } return return_msg; } //設(shè)置請(qǐng)求參數(shù)的值 private static String getRefunArgs(String out_trade_no,int total_fee,int refund_fee) { String nonce_str = WXPay.genNonceStr(); List<NameValuePair> packageParams = new LinkedList<NameValuePair>(); packageParams.add(new BasicNameValuePair("appid", Constants.APP_ID_WX)); packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID)); packageParams.add(new BasicNameValuePair("nonce_str", nonce_str)); packageParams.add(new BasicNameValuePair("op_user_id", Constants.MCH_ID)); packageParams.add(new BasicNameValuePair("out_refund_no",out_trade_no)); packageParams.add(new BasicNameValuePair("out_trade_no",out_trade_no)); packageParams.add(new BasicNameValuePair("refund_fee", String.valueOf(refund_fee))); packageParams.add(new BasicNameValuePair("total_fee", String.valueOf(total_fee))); String sign = WXPay.genPackageSign(packageParams); packageParams.add(new BasicNameValuePair("sign", sign)); return WXPay.toXml(packageParams); } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。