在开发中我们经常会使用到支付功能,目前国内使用频率高的支付方式有微信支付和支付宝支付,apple pay和三星pay没有深入研究过,我们暂时不考虑这两个支付。

下面我们来先讲讲支付的基本流程

A、客户端发起支付订单

不管是web端还是手机端,发起订单是都有对你发起的订单的数据进行签名(所谓的加密,目前大部分使用的是md5加密,可能还有SHA),加密过程一般都是在我们的服务器   上进行

B、支付宝微信服务器收到支付订单

加密之后我们都会使用post(get)向支付宝微信服务器发起一请求

C、支付宝微信服务器验证订单的合法性,扣钱,通知我们的服务器

接受到数据后会对我们提交的数据进行验证,所有支付开发不能再局域网中进行测试(推荐一个工具ngrok,不过国内被强,可以使用https://natapp.cn/),同样退款的也是一样的,但是退款需要的还更多,后面我们会单独说明

D、接受到支付宝微信服务器通知,验证消息的合法性,业务处理

接受到通知我们要对数据进行解密验证合法性(在这个步骤很多人为了省事情,把验证环节省了,这个可能会出现模拟支付成功消息,这样会造成问题)

E、发通知告诉支付宝微信服务器收到支付成功消息

F、退款,如果有涉及

现在我们对上面的支付过程进行抽象一下,发现支付的基本流程很相似,我们把其业务抽象出来

1、获取发起订单的参数(id是订单号)

public abstract Map<String, Object> getParameterMap(String id, HttpServletRequest request);

2、订单合法性验证

public abstract boolean verifyNotify(String id, HttpServletRequest request);

3、通知支付吧微信服务器支付成功消息收到

public abstract String getNotifyMessage(String id, HttpServletRequest request);

4、编码方式

public abstract String getRequestCharset();

5、关于签名方法我思考了很久是否放在抽象类中,后面还觉得不放进来(因为和支付的业务流程没多少关系),我会将其放在工具类中

好的那么现在我们就抽象出一个支付的流程类(PaymentPlugin)

package test;import java.util.Map;import javax.servlet.http.HttpServletRequest;public abstract class PaymentPlugin {public enum NotifyMethod {/** 同步 */sync,/** 异步 */async}/*** 1、获取发起订单的参数(id是订单号)*/public abstract Map<String, Object> getParameterMap(String id, HttpServletRequest request); /*** 2、订单合法性验证*/public abstract boolean verifyNotify(String id,  HttpServletRequest request);/*** 3、通知支付吧微信服务器支付成功消息收到*/public abstract String getNotifyMessage(NotifyMethod notifyMethod, HttpServletRequest request);/*** 4、编码方式*/public abstract String getRequestCharset();}

下面我们先来说说支付宝支付

支付宝支付有银行支付、支付宝双接口(即时到账支付、担保支付)、移动支付等几种,原来上基本一致,只是在签名和参与签名的参数上有细微的差别,我们在这儿就不过多深究,我们以支付宝双接口为例子

具体的参数要求我就不过多去说明,请参考支付宝的API

1、为了方便我会模拟一个订单类(一般是存库的),大家可以结合物业自行处理

public class Payment {private String id;private Type type;private BigDecimal amount;public String getId() {return id;}public void setId(String id) {this.id = id;}public Type getType() {return type;}public void setType(Type type) {this.type = type;}public BigDecimal getAmount() {return amount;}public void setAmount(BigDecimal amount) {this.amount = amount;}}

2、为了方便获取支付时需要用到的支付宝、微信给的参数(什么appid、partner的)我们新建一个类(一般也是存库方便修改,我们就模拟一下)

public class PluginConfig {private Map<String, String> attributes = new HashMap<String, String>();public Map<String, String> getAttributes() {return attributes;}public void setAttributes(Map<String, String> attributes) {this.attributes = attributes;}}
public class AlipayDualPlugin extends PaymentPlugin{protected Payment getPayment(String id) {//模拟查库过程Payment payment = new Payment();payment.setId("1");payment.setAmount(new BigDecimal("0.01"));return payment;}protected  PluginConfig getPluginConfig() {//模拟获取支付所需的参数PluginConfig pluginConfig = new PluginConfig();return pluginConfig;}//获取回调地址protected String getNotifyUrl(String id, NotifyMethod notify) {if (notify==NotifyMethod.sync) {//返回订单地址return "http://XXXXX.com/oder/" + id ;}//返回回调地址return  "http://XXXXX.com/payment/notify/" + id ;}@Overridepublic Map<String, Object> getParameterMap(String id,HttpServletRequest request) {Payment payment = getPayment(id);PluginConfig pluginConfig = getPluginConfig();Map<String, Object> parameterMap = new HashMap<String, Object>();parameterMap.put("service", "trade_create_by_buyer");parameterMap.put("partner", pluginConfig.getAttributes().get("partner"));parameterMap.put("_input_charset", "utf-8");parameterMap.put("sign_type", "MD5");//支付成功之后同步跳转的页面(一般跳转到订单页面)parameterMap.put("return_url", getNotifyUrl(id, NotifyMethod.sync));//支付成功之后支付宝服务器调用地址parameterMap.put("notify_url", getNotifyUrl(id, NotifyMethod.async));parameterMap.put("out_trade_no", id);parameterMap.put("subject", "");parameterMap.put("body", "");parameterMap.put("payment_type", "1");parameterMap.put("logistics_type", "EXPRESS");parameterMap.put("logistics_fee", "0");parameterMap.put("logistics_payment", "SELLER_PAY");parameterMap.put("price", payment.getAmount().setScale(2).toString());parameterMap.put("quantity", "1");parameterMap.put("seller_id",  pluginConfig.getAttributes().get("partner"));parameterMap.put("total_fee", payment.getAmount().setScale(2).toString());parameterMap.put("show_url", "");parameterMap.put("paymethod", "directPay");parameterMap.put("exter_invoke_ip", request.getLocalAddr());parameterMap.put("extra_common_param", "shopxx");parameterMap.put("sign", generateSign(parameterMap));return parameterMap;}//签名工具private String generateSign(Map<String, ?> parameterMap) {PluginConfig pluginConfig = getPluginConfig();return DigestUtils.md5Hex(joinKeyValue(new TreeMap<String, Object>(parameterMap), null,  pluginConfig.getAttributes().get("key"), "&", true, "sign_type", "sign"));}protected String joinKeyValue(Map<String, Object> map, String prefix, String suffix, String separator, boolean ignoreEmptyValue, String... ignoreKeys) {List<String> list = new ArrayList<String>();if (map != null) {for (Entry<String, Object> entry : map.entrySet()) {String key = entry.getKey();String value = ConvertUtils.convert(entry.getValue());if (StringUtils.isNotEmpty(key) && !ArrayUtils.contains(ignoreKeys, key) && (!ignoreEmptyValue || StringUtils.isNotEmpty(value))) {list.add(key + "=" + (value != null ? value : ""));}}}return (prefix != null ? prefix : "") + StringUtils.join(list, separator) + (suffix != null ? suffix : "");}@Overridepublic boolean verifyNotify(String id, HttpServletRequest request) {PluginConfig pluginConfig = getPluginConfig();Payment payment = getPayment(id);if (generateSign(request.getParameterMap()).equals(request.getParameter("sign")) && pluginConfig.getAttributes().get("partner").equals(request.getParameter("seller_id")) && id.equals(request.getParameter("out_trade_no"))&& ("WAIT_SELLER_SEND_GOODS".equals(request.getParameter("trade_status")) || "TRADE_SUCCESS".equals(request.getParameter("trade_status")) || "TRADE_FINISHED".equals(request.getParameter("trade_status"))) && payment.getAmount().compareTo(new BigDecimal(request.getParameter("total_fee"))) == 0) {Map<String, Object> parameterMap = new HashMap<String, Object>();parameterMap.put("service", "notify_verify");parameterMap.put("partner", pluginConfig.getAttributes().get("partner"));parameterMap.put("notify_id", request.getParameter("notify_id"));if ("true".equals(post("https://mapi.alipay.com/gateway.do", parameterMap))) {return true;}}return false;}protected String post(String url, Map<String, Object> parameterMap) {Assert.hasText(url);String result = null;HttpClient httpClient = new DefaultHttpClient();try {HttpPost httpPost = new HttpPost(url);List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();if (parameterMap != null) {for (Entry<String, Object> entry : parameterMap.entrySet()) {String name = entry.getKey();String value = ConvertUtils.convert(entry.getValue());if (StringUtils.isNotEmpty(name)) {nameValuePairs.add(new BasicNameValuePair(name, value));}}}httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));HttpResponse httpResponse = httpClient.execute(httpPost);HttpEntity httpEntity = httpResponse.getEntity();result = EntityUtils.toString(httpEntity);EntityUtils.consume(httpEntity);} catch (ClientProtocolException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {httpClient.getConnectionManager().shutdown();}return result;}@Overridepublic String getNotifyMessage(NotifyMethod notifyMethod, HttpServletRequest request) {if (notifyMethod == NotifyMethod.async) {return "success";}return null;}@Overridepublic String getRequestCharset() {return "UTF-8";}}

接下来我们说一下微信支付,同样的微信支付也有很多种,公众号支付、扫码支付(web端和线下支付)、app支付等,下面我为与公众号支付为例

public class WeixinPayPlugin extends PaymentPlugin{protected Payment getPayment(String id) {//模拟查库过程Payment payment = new Payment();payment.setId("1");payment.setAmount(new BigDecimal("0.01"));return payment;}protected static  PluginConfig getPluginConfig() {//模拟获取支付所需的参数PluginConfig pluginConfig = new PluginConfig();return pluginConfig;}//获取回调地址protected String getNotifyUrl(String id, NotifyMethod notify) {if (notify==NotifyMethod.sync) {//返回订单地址return "http://XXXXX.com/oder/" + id ;}//返回回调地址return  "http://XXXXX.com/payment/notify/" + id ;}@Overridepublic Map<String, Object> getParameterMap(String id,HttpServletRequest request) {Payment payment = getPayment(id);PluginConfig pluginConfig = getPluginConfig();SortedMap<String, Object> parameterMap = new TreeMap<String, Object>();parameterMap.put("appid",  pluginConfig.getAttributes().get("appid"));parameterMap.put("mch_id",pluginConfig.getAttributes().get("mch_id"));parameterMap.put("nonce_str", getRandomString(32));parameterMap.put("body","");parameterMap.put("out_trade_no", id);parameterMap.put("fee_type", "CNY");BigDecimal total = payment.getAmount().multiply(new BigDecimal(100));java.text.DecimalFormat df=new java.text.DecimalFormat("0");parameterMap.put("total_fee", df.format(total));parameterMap.put("spbill_create_ip", request.getLocalAddr());parameterMap.put("notify_url",  getNotifyUrl(id, NotifyMethod.async));parameterMap.put("trade_type", "NATIVE");parameterMap.put("product_id","");String sign = createSign("UTF-8", parameterMap);parameterMap.put("sign", sign);String requestXML = getRequestXml(parameterMap);String result = httpsRequest("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST",requestXML);Map<String, Object> map = null;try {map = doXMLParse(result);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} return map;}@Overridepublic boolean verifyNotify(String id, HttpServletRequest request) {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");// 获取微信调用我们notify_url的返回信息Map<Object, Object> map = doXMLParse(result);if (map.get("result_code").toString().equalsIgnoreCase("SUCCESS")) {SortedMap<String, Object> parameterMap = new TreeMap<String, Object>();String sign = (String) map.get("sign");for (Object keyValue : map.keySet()) {if(!keyValue.toString().equals("sign")){parameterMap.put(keyValue.toString(), map.get(keyValue));}}String createSign = createSign("UTF-8", parameterMap);if(createSign.equals(sign)){return true;}else{return false;}}return false;}@Overridepublic String getNotifyMessage(NotifyMethod notifyMethod,HttpServletRequest request) {if (notifyMethod == NotifyMethod.async) {return "success";}return null;}@Overridepublic String getRequestCharset() {return "UTF-8";}//随机字符串生成public static String getRandomString(int length) { //length表示生成字符串的长度    String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";       Random random = new Random();       StringBuffer sb = new StringBuffer();       for (int i = 0; i < length; i++) {       int number = random.nextInt(base.length());       sb.append(base.charAt(number));       }       return sb.toString();       }  //请求xml组装public static String getRequestXml(SortedMap<String,Object> parameters){StringBuffer sb = new StringBuffer();sb.append("<xml>");Set es = parameters.entrySet();Iterator it = es.iterator();while(it.hasNext()) {Map.Entry entry = (Map.Entry)it.next();String key = (String)entry.getKey();String value = (String)entry.getValue();if ("attach".equalsIgnoreCase(key)||"body".equalsIgnoreCase(key)||"sign".equalsIgnoreCase(key)) {sb.append("<"+key+">"+"<![CDATA["+value+"]]></"+key+">");}else {sb.append("<"+key+">"+value+"</"+key+">");}}sb.append("</xml>");return sb.toString();}//生成签名public static String createSign(String characterEncoding,SortedMap<String,Object> parameters){PluginConfig pluginConfig = getPluginConfig();StringBuffer sb = new StringBuffer();Set es = parameters.entrySet();Iterator it = es.iterator();while(it.hasNext()) {Map.Entry entry = (Map.Entry)it.next();String k = (String)entry.getKey();Object v = entry.getValue();if(null != v && !"".equals(v)&& !"sign".equals(k) && !"key".equals(k)) {sb.append(k + "=" + v + "&");}}sb.append("key=" + pluginConfig.getAttributes().get("appid"));String sign = MD5Encode(sb.toString(), characterEncoding).toUpperCase();return sign;}//请求方法public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {try {URL url = new URL(requestUrl);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setDoOutput(true);conn.setDoInput(true);conn.setUseCaches(false);// 设置请求方式(GET/POST)conn.setRequestMethod(requestMethod);conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");// 当outputStr不为null时向输出流写数据if (null != outputStr) {OutputStream outputStream = conn.getOutputStream();// 注意编码格式outputStream.write(outputStr.getBytes("UTF-8"));outputStream.close();}// 从输入流读取返回内容InputStream inputStream = conn.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String str = null;StringBuffer buffer = new StringBuffer();while ((str = bufferedReader.readLine()) != null) {buffer.append(str);}// 释放资源bufferedReader.close();inputStreamReader.close();inputStream.close();inputStream = null;conn.disconnect();return buffer.toString();} catch (ConnectException ce) {System.out.println("连接超时:{}"+ ce);} catch (Exception e) {System.out.println("https请求异常:{}"+ e);}return null;}//退款的请求方法public static String httpsRequest2(String requestUrl, String requestMethod, String outputStr,String PaymentPluginId) throws Exception {KeyStore keyStore  = KeyStore.getInstance("PKCS12");StringBuilder res = new StringBuilder("");SSLContext sslcontext=null;if(PaymentPluginId.equals("weixinAppPay")){FileInputStream instream = new FileInputStream(new File("/home/apiclient_cert.p12"));try {keyStore.load(instream, "13XXXXXXXX".toCharArray());} finally {instream.close();}sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, "13XXXXXXXXX".toCharArray()).build();}else{FileInputStream instream = new FileInputStream(new File("/home/apiclient_cert2.p12"));try {keyStore.load(instream, "1XXXXXXXXXX".toCharArray());} finally {instream.close();}sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, "1XXXXXXXXXXXX".toCharArray()).build();}// Trust own CA and all self-signed certs// Allow TLSv1 protocol onlySSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext,new String[] { "TLSv1" },null,SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();try {HttpPost httpost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");httpost.addHeader("Connection", "keep-alive");httpost.addHeader("Accept", "*/*");httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");httpost.addHeader("Host", "api.mch.weixin.qq.com");httpost.addHeader("X-Requested-With", "XMLHttpRequest");httpost.addHeader("Cache-Control", "max-age=0");httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");StringEntity entity2 = new StringEntity(outputStr ,Consts.UTF_8);httpost.setEntity(entity2);CloseableHttpResponse response = httpclient.execute(httpost);try {HttpEntity entity = response.getEntity();if (entity != null) {BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));String text;while ((text = bufferedReader.readLine()) != null) {res.append(text);}}EntityUtils.consume(entity);} finally {response.close();}} finally {httpclient.close();}return res.toString();}//xml解析public static Map doXMLParse(String strxml) throws JDOMException, IOException {strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");if(null == strxml || "".equals(strxml)) {return null;}Map m = new HashMap();InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));SAXBuilder builder = new SAXBuilder();Document doc = builder.build(in);Element root = doc.getRootElement();List list = root.getChildren();Iterator it = list.iterator();while(it.hasNext()) {Element e = (Element) it.next();String k = e.getName();String v = "";List children = e.getChildren();if(children.isEmpty()) {v = e.getTextNormalize();} else {v = getChildrenText(children);}m.put(k, v);}//关闭流in.close();return m;}public static String getChildrenText(List children) {StringBuffer sb = new StringBuffer();if(!children.isEmpty()) {Iterator it = children.iterator();while(it.hasNext()) {Element e = (Element) it.next();String name = e.getName();String value = e.getTextNormalize();List list = e.getChildren();sb.append("<" + name + ">");if(!list.isEmpty()) {sb.append(getChildrenText(list));}sb.append(value);sb.append("</" + name + ">");}}return sb.toString();}public static String setXML(String return_code, String return_msg) {return "<xml><return_code><![CDATA[" + return_code+ "]]></return_code><return_msg><![CDATA[" + return_msg+ "]]></return_msg></xml>";}  private static String byteArrayToHexString(byte b[]) {StringBuffer resultSb = new StringBuffer();for (int i = 0; i < b.length; i++)resultSb.append(byteToHexString(b[i]));return resultSb.toString();}private static String byteToHexString(byte b) {int n = b;if (n < 0)n += 256;int d1 = n / 16;int d2 = n % 16;return hexDigits[d1] + hexDigits[d2];}public static String MD5Encode(String origin, String charsetname) {String resultString = null;try {resultString = new String(origin);MessageDigest md = MessageDigest.getInstance("MD5");if (charsetname == null || "".equals(charsetname))resultString = byteArrayToHexString(md.digest(resultString.getBytes()));elseresultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));} catch (Exception exception) {}return resultString;}private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5","6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
}

主要的方法都包含在上面了,这个代码是扣出来的,未进行验证,但是获取参数、微信的预支付、回调的验证方法是一定正确的,包括微信支付的退款(这里强调一下,需要去微信支付官网下载证书,Java的需要p12)支付宝退款就不整理,直接贴一下

public Map<String, Object> getRefundParameterMap(Long id, HttpServletRequest request) {Map<String, Object> refundParameterMap = new HashMap<String, Object>();refundParameterMap.put("service", "refund_fastpay_by_platform_pwd");refundParameterMap.put("partner", "");refundParameterMap.put("_input_charset", "utf-8");refundParameterMap.put("sign_type", "MD5");refundParameterMap.put("notify_url",  "");refundParameterMap.put("seller_email", ".com");refundParameterMap.put("seller_id", "");refundParameterMap.put("refund_date", DateUtils.format(new Date(), DateUtils.FORMAT_LONG));refundParameterMap.put("batch_no", DateUtils.format(new Date(), DateUtils.FORMAT_DATE)+ refunds.getSn());refundParameterMap.put("batch_num", "1");refundParameterMap.put("detail_data", generateDetailData(refunds));refundParameterMap.put("sign", generateSign(refundParameterMap));return refundParameterMap;}private String generateDetailData(Refunds refunds) {Set<Payment> paymentSet =  refunds.getOrder().getPayments();List<Payment> paymentList = new ArrayList<Payment>(paymentSet);Payment payment = null;if(null!=paymentList){payment=paymentList.get(0);}StringBuffer data = new StringBuffer();data.append(payment.getTradeNo());data.append("^");java.text.DecimalFormat df=new java.text.DecimalFormat("0.00");data.append(df.format(refunds.getAmount()));data.append("^");data.append("协商退款");return data.toString();}
public boolean verifyNotify(HttpServletRequest request){if (generateSign(request.getParameterMap()).equals(request.getParameter("sign"))) {Map<String, Object> parameterMap = new HashMap<String, Object>();parameterMap.put("service", "notify_verify");parameterMap.put("partner", "2088311389671021");parameterMap.put("notify_id", request.getParameter("notify_id"));if ("true".equals(post("https://mapi.alipay.com/gateway.do", parameterMap))) {return true;}}return false;}

退款方法也可以方法接口中,刚开始考虑不周全,大家可以补一下

package test;import java.util.Map;import javax.servlet.http.HttpServletRequest;public abstract class PaymentPlugin {public enum NotifyMethod {/** 同步 */sync,/** 异步 */async}/*** 1、获取发起订单的参数(id是订单号)*/public abstract Map<String, Object> getParameterMap(String id, HttpServletRequest request); /*** 2、订单合法性验证*/public abstract boolean verifyNotify(String id,  HttpServletRequest request);/*** 3、通知支付吧微信服务器支付成功消息收到*/public abstract String getNotifyMessage(NotifyMethod notifyMethod, HttpServletRequest request);/*** 4、编码方式*/public abstract String getRequestCharset();/*** *退款接口*/public abstract Map<String, Object>  getRefundParameterMap (String id, HttpServletRequest request);
}

Java 关于支付的实现(微信、支付宝)相关推荐

  1. h5支付不能打开支付宝 ios_IOS H5支付调起微信支付宝客户端问题总结

    IOS H5支付调起微信支付宝客户端问题总结 很早之前公司的支付功能,通过H5去支付宝和微信支付,开始使用的是UIwebView来加载h5页面,当初只有支付宝网页支付形式,所以没有考虑到那么多,现在新 ...

  2. 基于spring-boot+uni-app实现app支付功能(微信/支付宝)服务端

    基于spring-boot+uni-app实现app支付功能(微信/支付宝)服务端 支付宝支付 1 准备工作 申请支付能力 接口加签方式 2代码 依赖 支付宝支付配置类 支付宝控制层 异步通知 微信支 ...

  3. 个人免签支付如何对接微信支付宝?

    个人开发者个人站长在使用用是离不开支付渠道的,但如果用官方的支付接口,还需要准备企业资质等,大大增加了开发流程和时间成本,而个人免签支付就是一个很不错的选择,所以我们今天就来说说怎么用个人免签支付对接 ...

  4. 记录自己的支付集成(微信支付宝)

    首先,作为一个菜鸟表示,虽然网上的集成框架很多,但是我要自己写,就算被坑的死去活来也要自己写. 1. 支付宝 这个支付宝的文档是个好东西,挺简单,挺容易看懂的,其次还有沙箱测试,表示支付宝一次通过很开 ...

  5. Java第三方支付接入案例(支付宝)

    开源项目链接 Kitty 开源权限管理系统 项目地址:https://gitee.com/liuge1988/kitty 演示地址:http://139.196.87.48:9002/kitty 用户 ...

  6. 微信支付服务器错误,【支付问题】微信支付宝支付超时、支付异常解决办法

    微信支付宝支付异常解决办法 只要用户在手机上支付成功,钱一定会到商户的账户上. 只要用户在手机上支付成功,钱一定会到商户的账户上. 只要用户在手机上支付成功,钱一定会到商户的账户上. 正常情况下,用户 ...

  7. 11支付功能≠支付系统:微信支付宝通用支付系统开发实战

    支付的代码只需十行,项目的代码请查看https://github.com/TLR2019/xc-edu02 1 微信支付 1.1 下单生成二维码 二维码可以利用下图的请求参数生成(下图没有截全,详系参 ...

  8. 澳洲支付服务商RoyalPay微信支付宝APP支付对接

    最近项目中需要开发澳洲那边的微信支付宝支付,所以去研究了一下微信境外支付,发现境外只支持服务商模式,即客户需要去与澳洲本地服务商合作,由客户提供材料,服务商帮客户申请支付相关账号,然后调用服务商提供的 ...

  9. java app支付_java实现微信App支付

    废话不多说,直接上代码,微信的小程序,公众号支付都大差不差,自行看文档修改参数即可. maven依赖: com.github.wxpay wxpay-sdk 0.0.3 application.yml ...

  10. java 实现支付功能_java程序支付宝接口付费功能的实现

    以前做过c#应用程序支付宝api接口功能,现在转移到Java程序上,代码如何实现呢? 1.从你的网站提交到支付宝: /** * 将订单提交支付宝进行网上支付 */ public ActionForwa ...

最新文章

  1. Beginning C# Objects 读书笔记(一)
  2. 在Spring Boot中使用 @ConfigurationProperties 注解
  3. DELPHI设置枚举类型size
  4. java 日期类代码_java 日期时间处理类
  5. bigquery_到Google bigquery的sql查询模板,它将您的报告提升到另一个层次
  6. python课程ppt_Python电子教学课件12程序设计基本方法.ppt
  7. django前端引用数据_Django 前后台的数据传递
  8. 构建Electron的常见问题(Mac)
  9. c#退出窗口跳转_详解C#切换窗口
  10. MongoDB集群配置
  11. Quartus II文件编译下载和USB-Blaster驱动安装
  12. android 6 root权限,「经验」android手机怎么开启Root权限
  13. python配置MySQL,需安装MySQL-pyt…
  14. html判断闰年,javascript怎么判断是否闰年?
  15. HDFS的读写流程步骤(附图文解析)
  16. 10、刷牛客网SQL题(四)
  17. 如何改变坏习惯,形成新习惯
  18. 【树链剖分】【模板】树的统计(P2590)
  19. 使用WASD键移动对象
  20. 利用电脑投放手机声音且可不冲突同时播放电脑声音的方法

热门文章

  1. mybatis Example
  2. 手机APP入门—常见功能点测试(有参考)
  3. Python模块卸载
  4. 坚果投影携手徕卡研发的坚果J10S,5000元价位段竟稳居榜首?
  5. 2017-12-01 中英文代码对比之ZLOGO 4 LOGO
  6. python实现之初等函数一
  7. 百趣生物技术介绍 | iTRAQ/TMT标记定量蛋白质组研究
  8. android 卡片滑动详情页,在Mugeda中制作顺畅的左右滑动切换卡片效果的教程
  9. Vue.js--计算属性
  10. 风华秋实上市失利:招股文件“失效”,严重依赖鹿晗和腾讯音乐