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

智能推荐

02-CSS高级技巧_风不识途的博客-程序员宅基地

文章目录一、精灵图二、字体图标三、鼠标样式四、表单的轮廓线 outline五、防止拖拽文本域 resize六、图片、表单和文字对齐七、解决图片底部默认空白缝隙问题八、文本溢出显示省略号九、布局技巧十、CSS初始化一、精灵图1、为什么需要精灵图?一个网页中往往会应用很多很小的背景图像作为装饰,当网页中图像过多时,服务器会频繁接收和发送请求图片,造成服务器压力过大,这大大降低页面的加载速度...

Oracle报00439原因,ORA-00439未启用的功能:DEFERRED_SEGMENT_CREATION_小田linda的博客-程序员宅基地

Oracle数据库版本都是11.2.0.1.0,操作系统都是WIN2008 (64位),用impdp工具,将数据从A服务器导入B服务器时,提示错误:ORA-004Oracle数据库版本都是11.2.0.1.0,操作系统都是WIN2008 (64位),用impdp工具,将数据从A服务器导入B服务器时,提示错误:ORA-00439 未启用的功能:DEFERRED_SEGMENT_CREATION。1、...

Linux源码包和rpm包的安装管理-运维工程师的自我救赎_欧阳文轩的博客-程序员宅基地

Linux源码包和rpm包的安装管理概要一、Linux软件包分类1. 源码包2. 二进制包(RPM包、系统默认包)3.脚本安装包二、rpm命令管理1.RPM包命名规则2.安装命令3.升级与卸载4.RPM包查询5.RPM包校验三、yum在线管理四、源码包管理1. 源码包与RPM包的区别2. 源码包安装过程五、脚本安装包概要软件安装对于操作系统来说是常用的操作,那如何在Linux中使用命令进行软件...

SVN客户端的下载安装_歪才的博客-程序员宅基地

TortoiseSVN 是 Subversion 版本控制系统的一个免费开源客户端,可以超越时间的管理文件和目录。文件保存在中央版本库,除了能记住文件和目录的每次修改以外,版本库非常像普通的文件服务器。你可以将文件恢复到过去的版本,并且可以通过检查历史知道数据做了哪些修改,谁做的修改。这就是为什么许多人将 Subversion 和版本控制系统看作一种“时间机器”。

document.all与WEB标准 _jxufewbt的博客-程序员宅基地

1、DOM  WEB标准现在可真是热门中热门,不过下面讨论的是一个不符合标准的document.all[]。DOM--DOCUMENT OBJECT MODEL文档对象模型,提供了访问文档对象的方法.例如文档中有一个table,你要改变它的背景颜色,那就可以在javascript中用document.all[]访问这个TABLE。但DOM也有所不同,因为浏览器厂商之间的竞争,各浏览器厂商都开发了自

Hibernate框架_姜同学的学习笔记的博客-程序员宅基地_hibernate框架

Hibernate框架1、简介Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用。hibernate是一个ORM框架。ORM的全拼是Object

随便推点

linux lsof命令详解,Linux lsof命令详解(每日一令之二十)_蒋融的博客-程序员宅基地

学习下lsof命令lsof全名list opened files,也就是列举系统中已经被打开的文件。我们都知道,linux环境中,任何事物都是文件,设备是文件,目录是文件,甚至sockets也是文件。所以,用好lsof命令,对日常的linux管理非常有帮助。lsof是linux最常用的命令之一,通常的输出格式为:引用COMMAND PID USER FD TYPE ...

linux raid gpt,linux – 调整RAID1磁盘阵列中的openSUSE 12.3 GPT ext4分区_weixin_39928768的博客-程序员宅基地

我有一个软件raid配置(/ dev / md2),它从两个3TB磁盘(sda和sdb)分配了分区sda3和sdb3.分区类型是GPT而不是LVM,文件系统是ext4.现在,根分区占用1TB,主分区(raid / dev / md3上的sda4和sdb4)占用1.8TB,我想调整根分区的大小只需250GB,并将可用空间分配给主分区,所以它最终在md2中为250GB,在家中为2.5TB.为此,我读到...

mysql修改密码123456789_mysql8.0修改密码时:ERROR 1819 (HY000): Your password does not satisfy the current poli..._量子学园的博客-程序员宅基地

用临时密码进入mysql,修改密码时报错:mysql&gt; ALTER USER 'root'@'localhost' IDENTIFIED BY 'aA123456';ERROR 1819 (HY000): Your password does not satisfy the current policy requirements原因是mysql8.0版安全做的很到位,我们看一下8.0版的设置...

Sumblime Text 2 插件GBK Encoding Suppor和ZenCoding的安装方法_weixin_33924220的博客-程序员宅基地

先安装Package Control组件按Ctrl+`调出console(注:安装有QQ输入法的这个快捷键会有冲突的,输入法属性设置-输入法管理-取消热键切换至QQ拼音)粘贴以下代码到底部命令行并回车:import urllib2,os;pf='Package Control.sublime-package';ipp=sublime.installed_packages_pa...

cs寄存器 x86 特权模式_x86处理器中的CS与IP寄存器_风折翼的博客-程序员宅基地

2.10CS和IP(1)CS和IP是8086CPU中两个最关键的寄存器,它们指示了CPU当前要读取指令的地址。CS为代码段寄存器,IP为指令指针寄存器,从名称上我们可以看出它们和指令的关系。在8086PC机中,任意时刻,设CS中的内容为M,IP中的内容为N,8086CPU将从内存M*16+N单元开始,读取一条指令并执行。也可以这样表述:8086机中,任意时刻,CPU将CS:IP指向的内容当作指令...

计算机网络基础期末试题,计算机网络基础期末考试试题_钱康来的博客-程序员宅基地

网络基础 复习题计算机网络基础期末考试试题姓名:_______ 期号:_______ 成绩:________一、选择题1.网络最大的特点是( )A)资源共享 B) 数据处理C) 分布式处理D) 分担负荷2.按覆盖的地理范围进行分类,计算机网络可以分为三类( )A)局域网、广域网与X..25 B) 局域网、广域网与宽带网C)局域网、广域网与ATM网 D) 局域网、广域网与城域...

推荐文章

热门文章

相关标签