java服務(wù)器端微信、支付寶支付和退款功能
工作需要,寫了服務(wù)器端的支付和退款功能,包含微信和支付寶,網(wǎng)上也有很多demo可以借鑒,我把我的代碼放出來,寫的比較簡單,有問題的歡迎指正,大家一起學(xué)習(xí)。
微信支付需要調(diào)用微信的統(tǒng)一下單接口,而支付寶不用。
我寫的時候微信和支付寶都單獨寫了一個工具類,來調(diào)用支付,給前端返回需要的數(shù)據(jù)。
ps:支付是可以不需要服務(wù)器端的,不過為了安全一點點,所以前端需要調(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這個是商戶自己生成的唯一訂單號
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 {
/**
* 僅需對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 + "\"";
// 簽約賣家支付寶賬號
orderInfo += "&seller_id=" + "\"" + Constants.SELLER + "\"";
// 商戶網(wǎng)站唯一訂單號
orderInfo += "&out_trade_no=" + "\"" + out_trade_no + "\"";
// 商品名稱
orderInfo += "&subject=" + "\"" + subject + "\"";
// 商品詳情
orderInfo += "&body=" + "\"" + body + "\"";
// 商品金額
orderInfo += "&total_fee=" + "\"" + price + "\"";
// 服務(wù)器異步通知頁面路徑
orderInfo += "¬ify_url=" + "\"" + "填寫服務(wù)器的支付回調(diào)路徑" + "\"";
// 服務(wù)接口名稱, 固定值
orderInfo += "&service=\"mobile.securitypay.pay\"";
// 支付類型, 固定值
orderInfo += "&payment_type=\"1\"";
// 參數(shù)編碼, 固定值
orderInfo += "&_input_charset=\"utf-8\"";
// 設(shè)置未付款交易的超時時間
// 默認(rèn)30分鐘,一旦超時,該筆交易就會自動被關(guān)閉。
// 取值范圍:1m~15d。
// m-分鐘,h-小時,d-天,1c-當(dāng)天(無論交易何時創(chuàng)建,都在0點關(guān)閉)。
// 該參數(shù)數(shù)值不接受小數(shù)點,如1.5h,可轉(zhuǎn)換為90m。
orderInfo += "&it_b_pay=\"30m\"";
// extern_token為經(jīng)過快登授權(quán)獲取到的alipay_open_id,帶上此參數(shù)用戶將使用授權(quán)的賬戶進(jìn)行支付
// orderInfo += "&extern_token=" + "\"" + extern_token + "\"";
// 支付寶處理完請求后,當(dāng)前頁面跳轉(zhuǎn)到商戶指定頁面的路徑,可空
orderInfo += "&return_url=\"m.alipay.com\"";
// 調(diào)用銀行卡支付,需配置此參數(shù),參與簽名, 固定值 (需要簽約《無線銀行卡快捷支付》才能使用)
// 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="退款出錯";
}
return strResponse;
微信
public class WXRefund {
private static final String url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
/**
* 微信退款
* @param out_trade_no 商戶訂單號
* @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證書 是從微信商戶平臺-》賬戶設(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è)置請求參數(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);
}
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
攜程Apollo(阿波羅)安裝部署以及java整合實現(xiàn)
這篇文章主要介紹了攜程Apollo(阿波羅)安裝部署以及java整合實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
關(guān)于@Scheduled注解的任務(wù)為什么不執(zhí)行的問題
這篇文章主要介紹了關(guān)于@Scheduled注解的任務(wù)為什么不執(zhí)行的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09
JAVA 多態(tài)操作----父類與子類轉(zhuǎn)換問題實例分析
這篇文章主要介紹了JAVA 多態(tài)操作----父類與子類轉(zhuǎn)換問題,結(jié)合實例形式分析了JAVA 多態(tài)操作中父類與子類轉(zhuǎn)換問題相關(guān)原理、操作技巧與注意事項,需要的朋友可以參考下2020-05-05
SpringBoot整合MyBatis Plus實現(xiàn)基本CRUD與高級功能
Spring Boot是一款用于快速構(gòu)建Spring應(yīng)用程序的框架,而MyBatis Plus是MyBatis的增強(qiáng)工具,本文將詳細(xì)介紹如何在Spring Boot項目中整合MyBatis Plus,并展示其基本CRUD功能以及高級功能的實現(xiàn)方式,需要的朋友可以參考下2024-02-02

