java版+支付宝支付和微信支付(一)(含源码)_代码催人老的博客-程序员宅基地

技术标签: 支付宝  java  支付  微信  支付宝支付  微信支付  

最近公司在做支付模块,在接入过程中遇到了很多坑,费了不少事,现在分享一下接入方法,也记录一下,以后可能还用的到。用的是支付宝的即时到帐支付功能和微信的扫码支付功能,相比起来,个人感觉支付宝的文档和接入方式都比微信的容易理解和操作,也不用自己写页面,接入起来比较方便,毕竟是支付起家的,比微信支付少很多坑,下面就分别介绍着两种支付的接入方法。

支付宝支付

1、申请签约

目的是得到开发使用的合作伙伴身份(PID)和MD5秘钥,申请地址(即时到账收款):https://b.alipay.com/order/productDetail.htm?productId=2015110218012942


申请方式在开放平台的文档上有详细说明,这里就不再赘述。

2、接入支付接口

在得到PID和秘钥后就可以接入接口了,首先在开放平台中下载官方的demo(java+MD5版本),支付宝的demo做的非常好,下载下来直接配置下jdk就可以运行了。如果遇到Java compiler level does not match错误,说明你用的eclipse或myeclipse的jdk编译版本与demo的JDK编译版本不一致,修改下jdk编译版本就可以了。其实就用到了4个类,如下图
项目目录
可以选择把支付功能单独做一个项目,在其他项目调用接口就可以支付,也可以整合到自己的项目里,为了好维护我整合到自己的项目里了。把这四个类放到自己的项目中,引入相应的jar包

2.1、demo中类的说明

AlipayConfig.java类主要是配置参数信息的类

package com.fahai.pay.alipay;

import com.fahai.utils.ProInfoUtil;

/* *
 *类名:AlipayConfig
 *功能:基础配置类
 *详细:设置帐户有关信息及返回路径
 *版本:3.4
 *修改日期:2016-03-08
 *说明:
 *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
 *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
 */

public class AlipayConfig {
    
//↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
	// 合作身份者ID,签约账号,以2088开头由16位纯数字组成的字符串,查看地址:https://b.alipay.com/order/pidAndKey.htm
	public static String partner = "你自己的PID";
	// 收款支付宝账号,以2088开头由16位纯数字组成的字符串,一般情况下收款账号就是签约账号
	public static String seller_id = partner;
	// MD5密钥,安全检验码,由数字和字母组成的32位字符串,查看地址:https://b.alipay.com/order/pidAndKey.htm
    public static String key = "你自己的MD5秘钥";
	// 服务器异步通知页面路径  需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
//异步通知页面,就是接受支付宝支付结果返回信息的Controller,可以处理自己的支付后的逻辑
    //测试环境
	public static String notify_url = ProInfoUtil.getInstance().getProperty("project_url")+"order/pay/aliPayOrder";

	// 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
	//同步跳转的页面,就是支付宝支付成功后页面跳转的url
	public static String return_url = ProInfoUtil.getInstance().getProperty("project_url")+"order/pay/payResponse";

	// 签名方式
	public static String sign_type = "MD5";
	
	// 调试用,创建TXT日志文件夹路径,见AlipayCore.java类中的logResult(String sWord)打印方法。
	public static String log_path = "C:\\";
		
	// 字符编码格式 目前支持 gbk 或 utf-8
	public static String input_charset = "utf-8";
		
	// 支付类型 ,无需修改
	public static String payment_type = "1";
		
	// 调用的接口名,无需修改
	public static String service = "create_direct_pay_by_user";


//↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
	
//↓↓↓↓↓↓↓↓↓↓ 请在这里配置防钓鱼信息,如果没开通防钓鱼功能,为空即可 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
	
	// 防钓鱼时间戳  若要使用请调用类文件submit中的query_timestamp函数
	public static String anti_phishing_key = "";
	
	// 客户端的IP地址 非局域网的外网IP地址,如:221.0.0.1
	public static String exter_invoke_ip = "";
		
//↑↑↑↑↑↑↑↑↑↑请在这里配置防钓鱼信息,如果没开通防钓鱼功能,为空即可 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
	
}

AlipayCore.java是整理参数的工具类

package com.alipay.util;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.httpclient.methods.multipart.FilePartSource;
import org.apache.commons.httpclient.methods.multipart.PartSource;

import com.alipay.config.AlipayConfig;

/* *
 *类名:AlipayFunction
 *功能:支付宝接口公用函数类
 *详细:该类是请求、通知返回两个文件所调用的公用函数核心处理文件,不需要修改
 *版本:3.3
 *日期:2012-08-14
 *说明:
 *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
 *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
 */

public class AlipayCore {

    /** 
     * 除去数组中的空值和签名参数
     * @param sArray 签名参数组
     * @return 去掉空值与签名参数后的新签名参数组
     */
    public static Map<String, String> paraFilter(Map<String, String> sArray) {

        Map<String, String> result = new HashMap<String, String>();

        if (sArray == null || sArray.size() <= 0) {
            return result;
        }

        for (String key : sArray.keySet()) {
            String value = sArray.get(key);
            if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
                || key.equalsIgnoreCase("sign_type")) {
                continue;
            }
            result.put(key, value);
        }

        return result;
    }

    /** 
     * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
     * @param params 需要排序并参与字符拼接的参数组
     * @return 拼接后字符串
     */
    public static String createLinkString(Map<String, String> params) {

        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);

        String prestr = "";

        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);

            if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
                prestr = prestr + key + "=" + value;
            } else {
                prestr = prestr + key + "=" + value + "&";
            }
        }

        return prestr;
    }

    /** 
     * 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
     * @param sWord 要写入日志里的文本内容
     */
    public static void logResult(String sWord) {
        FileWriter writer = null;
        try {
            writer = new FileWriter(AlipayConfig.log_path + "alipay_log_" + System.currentTimeMillis()+".txt");
            writer.write(sWord);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /** 
     * 生成文件摘要
     * @param strFilePath 文件路径
     * @param file_digest_type 摘要算法
     * @return 文件摘要结果
     */
    public static String getAbstract(String strFilePath, String file_digest_type) throws IOException {
        PartSource file = new FilePartSource(new File(strFilePath));
    	if(file_digest_type.equals("MD5")){
    		return DigestUtils.md5Hex(file.createInputStream());
    	}
    	else if(file_digest_type.equals("SHA")) {
    		return DigestUtils.sha256Hex(file.createInputStream());
    	}
    	else {
    		return "";
    	}
    }
}

AlipayNotify.java是验证签名的类

package com.alipay.util;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

import com.alipay.config.AlipayConfig;
import com.alipay.sign.MD5;

/* *
 *类名:AlipayNotify
 *功能:支付宝通知处理类
 *详细:处理支付宝各接口通知返回
 *版本:3.3
 *日期:2012-08-17
 *说明:
 *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
 *该代码仅供学习和研究支付宝接口使用,只是提供一个参考

 *************************注意*************************
 *调试通知返回时,可查看或改写log日志的写入TXT里的数据,来检查通知返回是否正常
 */
public class AlipayNotify {

    /**
     * 支付宝消息验证地址
     */
    private static final String HTTPS_VERIFY_URL = "https://mapi.alipay.com/gateway.do?service=notify_verify&";

    /**
     * 验证消息是否是支付宝发出的合法消息
     * @param params 通知返回来的参数数组
     * @return 验证结果
     */
    public static boolean verify(Map<String, String> params) {

        //判断responsetTxt是否为true,isSign是否为true
        //responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
        //isSign不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
    	String responseTxt = "false";
		if(params.get("notify_id") != null) {
			String notify_id = params.get("notify_id");
			responseTxt = verifyResponse(notify_id);
		}
	    String sign = "";
	    if(params.get("sign") != null) {sign = params.get("sign");}
	    boolean isSign = getSignVeryfy(params, sign);

        //写日志记录(若要调试,请取消下面两行注释)
        //String sWord = "responseTxt=" + responseTxt + "\n isSign=" + isSign + "\n 返回回来的参数:" + AlipayCore.createLinkString(params);
	    //AlipayCore.logResult(sWord);

        if (isSign && responseTxt.equals("true")) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 根据反馈回来的信息,生成签名结果
     * @param Params 通知返回来的参数数组
     * @param sign 比对的签名结果
     * @return 生成的签名结果
     */
	private static boolean getSignVeryfy(Map<String, String> Params, String sign) {
    	//过滤空值、sign与sign_type参数
    	Map<String, String> sParaNew = AlipayCore.paraFilter(Params);
        //获取待签名字符串
        String preSignStr = AlipayCore.createLinkString(sParaNew);
        //获得签名验证结果
        boolean isSign = false;
        if(AlipayConfig.sign_type.equals("MD5") ) {
        	isSign = MD5.verify(preSignStr, sign, AlipayConfig.key, AlipayConfig.input_charset);
        }
        return isSign;
    }

    /**
    * 获取远程服务器ATN结果,验证返回URL
    * @param notify_id 通知校验ID
    * @return 服务器ATN结果
    * 验证结果集:
    * invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空 
    * true 返回正确信息
    * false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
    */
    private static String verifyResponse(String notify_id) {
        //获取远程服务器ATN结果,验证是否是支付宝服务器发来的请求

        String partner = AlipayConfig.partner;
        String veryfy_url = HTTPS_VERIFY_URL + "partner=" + partner + "&notify_id=" + notify_id;

        return checkUrl(veryfy_url);
    }

    /**
    * 获取远程服务器ATN结果
    * @param urlvalue 指定URL路径地址
    * @return 服务器ATN结果
    * 验证结果集:
    * invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空 
    * true 返回正确信息
    * false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
    */
    private static String checkUrl(String urlvalue) {
        String inputLine = "";

        try {
            URL url = new URL(urlvalue);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection
                .getInputStream()));
            inputLine = in.readLine().toString();
        } catch (Exception e) {
            e.printStackTrace();
            inputLine = "";
        }

        return inputLine;
    }
}

AlipaySubmit.java模拟form表单请求支付宝支付接口的类

package com.alipay.util;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import com.alipay.config.AlipayConfig;
import com.alipay.sign.MD5;

/* *
 *类名:AlipaySubmit
 *功能:支付宝各接口请求提交类
 *详细:构造支付宝各接口表单HTML文本,获取远程HTTP数据
 *版本:3.3
 *日期:2012-08-13
 *说明:
 *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
 *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
 */

public class AlipaySubmit {
    
    /**
     * 支付宝提供给商户的服务接入网关URL(新)
     */
    private static final String ALIPAY_GATEWAY_NEW = "https://mapi.alipay.com/gateway.do?";
	
    /**
     * 生成签名结果
     * @param sPara 要签名的数组
     * @return 签名结果字符串
     */
	public static String buildRequestMysign(Map<String, String> sPara) {
    	String prestr = AlipayCore.createLinkString(sPara); //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
        String mysign = "";
        if(AlipayConfig.sign_type.equals("MD5") ) {
        	mysign = MD5.sign(prestr, AlipayConfig.key, AlipayConfig.input_charset);
        }
        return mysign;
    }
	
    /**
     * 生成要请求给支付宝的参数数组
     * @param sParaTemp 请求前的参数数组
     * @return 要请求的参数数组
     */
    private static Map<String, String> buildRequestPara(Map<String, String> sParaTemp) {
        //除去数组中的空值和签名参数
        Map<String, String> sPara = AlipayCore.paraFilter(sParaTemp);
        //生成签名结果
        String mysign = buildRequestMysign(sPara);

        //签名结果与签名方式加入请求提交参数组中
        sPara.put("sign", mysign);
        sPara.put("sign_type", AlipayConfig.sign_type);

        return sPara;
    }

    /**
     * 建立请求,以表单HTML形式构造(默认)
     * @param sParaTemp 请求参数数组
     * @param strMethod 提交方式。两个值可选:post、get
     * @param strButtonName 确认按钮显示文字
     * @return 提交表单HTML文本
     */
    public static String buildRequest(Map<String, String> sParaTemp, String strMethod, String strButtonName) {
        //待请求参数数组
        Map<String, String> sPara = buildRequestPara(sParaTemp);
        List<String> keys = new ArrayList<String>(sPara.keySet());

        StringBuffer sbHtml = new StringBuffer();

        sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\" action=\"" + ALIPAY_GATEWAY_NEW
                      + "_input_charset=" + AlipayConfig.input_charset + "\" method=\"" + strMethod
                      + "\">");

        for (int i = 0; i < keys.size(); i++) {
            String name = (String) keys.get(i);
            String value = (String) sPara.get(name);

            sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>");
        }

        //submit按钮控件请不要含有name属性
        sbHtml.append("<input type=\"submit\" value=\"" + strButtonName + "\" style=\"display:none;\"></form>");
        sbHtml.append("<script>document.forms['alipaysubmit'].submit();</script>");

        return sbHtml.toString();
    }
    
 
    
    /**
     * 用于防钓鱼,调用接口query_timestamp来获取时间戳的处理函数
     * 注意:远程解析XML出错,与服务器是否支持SSL等配置有关
     * @return 时间戳字符串
     * @throws IOException
     * @throws DocumentException
     * @throws MalformedURLException
     */
	public static String query_timestamp() throws MalformedURLException,
                                                        DocumentException, IOException {

        //构造访问query_timestamp接口的URL串
        String strUrl = ALIPAY_GATEWAY_NEW + "service=query_timestamp&partner=" + AlipayConfig.partner + "&_input_charset" +AlipayConfig.input_charset;
        StringBuffer result = new StringBuffer();

        SAXReader reader = new SAXReader();
        Document doc = reader.read(new URL(strUrl).openStream());

        List<Node> nodeList = doc.selectNodes("//alipay/*");

        for (Node node : nodeList) {
            // 截取部分不需要解析的信息
            if (node.getName().equals("is_success") && node.getText().equals("T")) {
                // 判断是否有成功标示
                List<Node> nodeList1 = doc.selectNodes("//response/timestamp/*");
                for (Node node1 : nodeList1) {
                    result.append(node1.getText());
                }
            }
        }

        return result.toString();
    }
}

这几个类调用支付宝接口的是AlipaySubmit,在网页选好购买的商品时,在系统中生成订单,然后进行支付,浏览器跳转到支付宝支付网站,Controller中代码为:

/**
     * 支付宝支付页面
     *
     * @return
     * @throws IOException 
     */
    @RequestMapping(value = "/aliPay")
    public void aliPay(HttpServletRequest request, HttpServletResponse response) throws IOException {
    	LOGGER.info("支付宝支付页面");
    	//商户订单号,商户网站订单系统中唯一订单号,必填
        String orderNo = request.getParameter("orderNo");
        //订单名称,必填
        String subjectName = request.getParameter("subjectName");
        //付款金额,必填
        String total_fee = request.getParameter("fee");
        //商品描述,可空
        String body = "法海风控 " + subjectName;
        if ("money".equals(body)) {
        	body = "法海风控  余额充值";
		}
		//把请求参数打包成map
		Map<String, String> sParaTemp = new HashMap<String, String>();
		sParaTemp.put("service", AlipayConfig.service);
        sParaTemp.put("partner", AlipayConfig.partner);
        sParaTemp.put("seller_id", AlipayConfig.seller_id);
        sParaTemp.put("_input_charset", AlipayConfig.input_charset);
		sParaTemp.put("payment_type", AlipayConfig.payment_type);
		sParaTemp.put("notify_url", AlipayConfig.notify_url);
		sParaTemp.put("return_url", AlipayConfig.return_url);
		sParaTemp.put("anti_phishing_key", AlipayConfig.anti_phishing_key);
		sParaTemp.put("exter_invoke_ip", AlipayConfig.exter_invoke_ip);
		sParaTemp.put("out_trade_no", orderNo);
		sParaTemp.put("subject", subjectName);
		sParaTemp.put("total_fee", total_fee);
		sParaTemp.put("body", body);
		//其他业务参数根据在线开发文档,添加参数.文档地址:https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.O9yorI&treeId=62&articleId=103740&docType=1
        //如sParaTemp.put("参数名","参数值");
		//建立请求
		String sHtmlText = AlipaySubmit.buildRequest(sParaTemp,"get","确认");
		response.setHeader("Content-Type", "text/html; charset=UTF-8");
		response.setCharacterEncoding("UTF-8");  
		PrintWriter out = response.getWriter();
		System.out.println(sHtmlText);
		out.println(sHtmlText);
    	
    }

请求aliPay会跳转到支付宝支付页面:
支付宝支付页面


3、接收支付结果通知

在配置好notify_url之后,支付结果会请求相应的接口,我的是order/pay/aliPayOrder,代码如下

/**
     * 支付宝支付订单
     * @return
     * @throws IOException 
     */
    @ResponseBody
    @RequestMapping(value = "pay/aliPayOrder", method = RequestMethod.POST)
    public void aliPayOrder(HttpServletRequest request,HttpServletResponse response) throws IOException {
    	LOGGER.info("支付订单");
    	
    	//从request中获得参数Map,并返回可读的Map 
    	Map<String, String> params = RequestUtil.getParameterMap(request);
    	LOGGER.info(params.toString());
    	//验证支付宝签名
    	boolean aliSign = AlipayNotify.verify(params);
    	if (aliSign) {//验证成功
    		//交易状态
    		String tradeStatus = params.get("trade_status");
    		//订单编号  		
    		String orderNo = params.get("out_trade_no");
    		//支付单号
    		String payNo = params.get("trade_no");
    		//支付账号
    		String payAccount = params.get("buyer_email");
    		//支付金额
    		String totalFee = params.get("total_fee");
    		//收款支付宝账号
    		String sellerId = params.get("seller_id");
    		if (Constant.ALIPAY_TRADE_SUCCESS.equals(tradeStatus)) {//支付宝支付状态为成功
    			//验证支付宝返回信息与请求信息一致
    			if (ProInfoUtil.getInstance().getProperty("alipay_partner").equals(sellerId)) {
    				//订单处理状态
    				String orderHandleStatus = "error";
    				//验证订单未做支付处理
        			Order order = orderService.queryOrderByOrderNo(orderNo);
        			//订单已支付
        			if (Constant.DEALSTATUS_PAY.equals(order.getDealStatus())) {
        				response.getWriter().print("success");
        				return;
					}
					if (null != order && Double.parseDouble(totalFee) == order.getDealPrice() && 
							Constant.DEALSTATUS_NOT_PAY.equals(order.getDealStatus())) {//验证金额是否和订单一致
						//更新订单为已支付、更新用户套餐余额、添加用户充值记录、添加用户余额支出记录
						order.setDealStatus(Constant.DEALSTATUS_PAY);
						order.setPayNo(payNo);
						order.setPayType(Constant.ALIPAY);
						order.setPayAccount(payAccount);
						try {
							//支付成功处理支付业务
							boolean result = orderService.payOrder(order);
							if (result) {
								//成功后向支付宝返回成功标志
								LOGGER.info("支付宝支付成功");
								orderHandleStatus = "success";
					    		response.getWriter().print("success");
							}
						} catch (Exception e) {
							e.printStackTrace();
							LOGGER.info("支付宝支付失败");
							response.getWriter().print("fail");
						}
						
					}
					//添加支付信息
					Map<String, Object> map = new HashMap<String, Object>();
					map.put("params", params.toString());
					map.put("payType", Constant.ALIPAY);
					map.put("orderNo", orderNo);
					map.put("handleStatus", orderHandleStatus);
					orderService.addPayInfo(map);
				}
			}
    		
		} else {//验证失败
			LOGGER.info("支付宝返回验证失败");
			response.getWriter().print("fail");
		}
    }


 /** 
  * 从request中获得参数Map,并返回可读的Map 
  *  
  * @param request 
  * @return 
  */  
 @SuppressWarnings("unchecked")  
 public static Map getParameterMap(HttpServletRequest request) {  
     // 参数Map  
     Map properties = request.getParameterMap();  
     // 返回值Map  
     Map<String, String> returnMap = new HashMap<String, String>();  
     Iterator entries = properties.entrySet().iterator();  
     Map.Entry entry;  
     String name = "";  
     String value = "";  
     while (entries.hasNext()) {  
         entry = (Map.Entry) entries.next();  
         name = (String) entry.getKey();  
         Object valueObj = entry.getValue();  
         if(null == valueObj){  
             value = "";  
         }else if(valueObj instanceof String[]){  
             String[] values = (String[])valueObj;  
             for(int i=0;i<values.length;i++){  
                 value = values[i] + ",";  
             }  
             value = value.substring(0, value.length()-1);  
         }else{  
             value = valueObj.toString();  
         }  
         returnMap.put(name, value);  
     }  
     return returnMap;  
 }  

至此,支付宝支付功能已经做完了,其中有几个细节需要添加,比如支付时查询订单状态是否已经支付,是否过期等等,可以根据自己的需求去完善。
支付宝的接入还是很顺利的,如果熟练的话一两天就可以完成了,刚开始写博客,有错误或者不明白的地方欢迎大家指出一起交流学习,共同进步。
由于篇幅问题,我在下一章介绍微信支付的接入。


由于个人原因,写完本文就很少上csdn,没想到这么多同学留言要源码,十分惶恐,十分内疚,恐怕是误导和耽误了很多同学,本人亦是讨厌留文不留码的行为,现在将源码献上,不过已经过了4年,支付功能已经改版多次,此源码仅供参考,更多的还是要看官方demo。
下载地址:https://download.csdn.net/download/qukaiwei/12091787

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qukaiwei/article/details/53925799

智能推荐

C语言进阶:字符函数和字符串函数_舟叶的博客-程序员宅基地

0.前言C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。字符串常量适用于那些对它不做修改的字符串函数。1. 函数介绍1.1 strlen求字符串长度size_t strlen ( const char * str );基本使用方式:#include &lt;stdio.h&gt;#include &lt;string.h&gt;int main(){ char arr[] = "hell...

windows 10 下撸pipenv 随记_杰然不同_的博客-程序员宅基地

pipenv简介略,自己百度)pipenv主要特性(略,自己百度)pipenv 都包含什么?(略,自己百度)1 安装pipenvpip install pipenv2 创建新的python版本环境1 mkdir project2 cd project3 pipenv install指定python版本pipenv --python 3pipenv ...

美化Ubuntu18.04 安装mac os主题_滕青山YYDS的博客-程序员宅基地_ubuntu安装mac主题

前言提示关于几个目录,GTK、Shell的目录是:/usr/share/themes,图标的目录是/usr/share/icons。放到/usr/share/下是全局修改,也就是说如果你换一个账户登陆,也是可以用这些主题文件的。弊端就是操作较复杂,需要sudo权限。如果仅仅是想修改当前账户的主题,可以选择在/home/YourAccount/(比如 /home/feipeng8848/)下新建两个目录:.themes 和 .icons。注意,目录名称前面有个点 “ . ” ,然后把shell、G

用Hadoop构建电影推荐系统_javastart的博客-程序员宅基地

用Hadoop构建电影推荐系统 2013-10-21 10:31| 发布者: 天空之城| 查看: 18598| 评论:1|原作者: 张丹(Conan)|来自:张丹的粉丝博客摘要: Netflix电影推荐的百万美金比赛,把“推荐”变成了时下最热门的数据挖掘算法之一。也正是由于Netflix的比赛,让企业界和学科界有了更深层次的技术碰撞。引发了各种网站“推荐”热

BNF范式和EBNF范式_tf1988的博客-程序员宅基地

1、什么是BNF范式,什么又是EBNF范式?答:巴科斯范式及其扩展(BNF & Augmented BNF)    1)巴科斯范式:巴科斯范式(BNF: Backus-Naur Form 的缩写)是由 John Backus 和 Peter Naur 首先引入的用来描述计

java set 删除_Java Set remove()用法及代码示例_weixin_39862669的博客-程序员宅基地

java.util.Set.remove(Object O)方法用于从Set中删除特定元素。用法:boolean remove(Object O)参数:参数O是此Set维护的元素类型,并指定要从Set中删除的元素。返回值:如果Set中存在指定的元素,则此方法返回True,否则返回False。以下示例程序旨在说明java.util.Set.remove(Object O)方法:// Java cod...

随便推点

NameNode 的信息存储(fsimage,edit log)_佩亦之的博客-程序员宅基地

1 概述HDFS中的NameNode被称为元数据节点DataNode称为数据节点。NameNode维护了文件与数据块的映射表以及数据块与数据节点的映射表,而真正的数据是存储在DataNode上。对于NameNode如何存储这些信息,它维护两个文件,一个是fsimage(file system image ),一个是editlog。2 fsimage与editlog作用1.fsimage保存...

关于hextoraw()与utl_raw.cast_to_raw及rawtohex() _ksark的博客-程序员宅基地

来源:http://flysky0814.itpub.net/post/35477/413779SQL&gt; create table test_raw (raw_col raw(10));表已创建。SQL&gt; insert into test_raw values (hextoraw('ff'));已创建 1 行。SQL&gt; insert into test_raw ...

jQuery实现影院选座订座效果_王同学要努力的博客-程序员宅基地_jquery电影选座

jQuery实现影院选座订座效果效果如下:代码如下:&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;head&gt; &lt;meta charset="utf-8"&gt; &lt;meta name="viewport" content="width=device-width; initial-scale=1.0"&gt; &lt;title&gt;jQuery影院选座订座效果代码&lt;/title&gt; &lt;meta n

APICloud数据云3.0使用教程_APICloud-移动端低代码开发平台的博客-程序员宅基地_apicloud 云数据库

数据云3.0是一个全新的服务端开发运维平台,提供从后端开发、接口联调到上线运营维护等一整套方案。开发者无需考虑数据库和服务器等基础设施,无需关心服务器测试环境的搭建,数据的备份及服务扩容等与业务无关的工作,只需关心逻辑本身。通过云引擎,云数据库,云函数,内置模型、等功能模块方便用户快速实现常用的后端功能。主要操作界面在APICloud开发平台开发控制台界面:云设置界面提供了一些全局设置的入口,这些全局设置在正式环境和测试环境中同时生效。可以进行接口验证设置和服务设置。数据模型主要是可以创

行人重识别02-05:fast-reid(BoT)-pytorch编程规范(fast-reid为例)2-DefaultTrainer解析_江南才尽,年少无知!的博客-程序员宅基地

通过上一篇博客。#在第一次迭代之前调用defafter_train(self)#在最后一次迭代之后调用defbefore_step(self)#在每次迭代之前调用defafter_step(self)#在每次迭代之后调用并且已经知道他是在什么时候被带哦用,同时知道了训练的大致过程。但是hooks是如何创建的,我们需要那些hooks,我们不是很清楚,接下来我们会为大家进行讲解。...

推荐文章

热门文章

相关标签