网站对接支付宝进行支付

       本文介绍PC网页对接支付宝,完成批量向支付宝账户转账的功能(使用Java实现),首先我的水平是这样的:接到这个工作任务后,可以说我是大白,之前我做过银行的项目,懂签名和验签是怎么一回事,但是对接支付宝,我是没有接触过;所以我这篇博客,是针对于没有任何思绪的童鞋,我尽量能详细就详细写,有不对的地方请指正。

目前我的实现:使用JavaWeb的servlet + jsp + rsa加密方式,对接支付宝“批量转账至支付宝账号”接口(有密接口,有密:即转账是需要用户输入支付密码),接口名称是:batch_trans_notify;发起付款成功后,采用异步通知的方式接到支付宝付款结果,然后对支付宝付款结果进行处理。另外,我是先做的demo,然后我采用springmvc框架将支付宝批量付款接口集成到我们正式项目中,项目运行完美。


业务场景:公司做了一个营销活动,大致就是邀请朋友买车成功后会给邀请人现金奖励,而这个现金奖励财务方面通过系统直接转账至邀请人支付宝账号。

下面我会详细介绍我从一个大白到我成功对接支付宝给我个人支付宝转账的例子。对接支付宝,主要分为两部分:第一,向支付宝发起付款;第二,接受支付宝款结果,如下图:

网站对接支付宝进行支付_第1张图片


网站对接支付宝进行支付_第2张图片

其中,准备工作重注册企业级支付宝账号、申请批量付款接口这两个步骤由自己公司申请,我们作为开发人员不做这个工作,因为申请时需要公司的一些信息什么的(我是公司A的员工,准确的说是公司A的开发人员,公司安排给我的任务是对接支付宝付款,那么就请公司为我提供付款账号(即:企业级支付宝账号));为什么要签约呢?这个很简单,你要用阿里支付宝的付款功能,人家马云 阿里公司说了,我提供服务,你得给我交手续费;这就相当于,你到超时买东西,付款时采用刷卡的方式,银行说了,你超市使用刷卡方式,pos机我提供,不过每次刷卡是要超市你掏手续费的,我记得银联刷卡银行向超市收取费用的标准是千分之三(每刷1000元付手续费3元,这个手续费用是超市付的;支付宝也一样,你要用支付宝付款,那么就得给人家手续费用,好了,不多说了,扯远了),如果注册企业级支付宝账号和申请批量有密付款接口有问题,可以直接拨打阿里服务热线,人家很热情的。 

       公司为我们申请好企业级支付宝并签约了批量有密付款接口后,作为开发人员,我们手里面会有这几样东西:企业级支付宝账号及登录密码、PID(这个PID就是支付宝给我们的合作伙伴ID 号 不知道如何获取,请参考 https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.dYvec2&treeId=64&articleId=104804&docType=1,大家在具体操作时,把这个文档大致浏览一下,好多东西,如果没有接触过没关系,看的次数多了,就有印象了,久而久之就熟悉了)。

       接下来,配置密钥,首先我先说明,密钥的重要性,密钥是用来加密解密的,我使用的rsa对称加密算法(对称就是配对的,就是A和B是一对密钥对,用A加密,必须用B解密,同样用B加密必须用A解密),在我工作历程中,凡是涉及付款,也就是和钱打交道的,肯定会加密,所以密钥很重要;我认为在对接支付宝批量付款接口的过程中,加密(可以理解为签名)和解密(解密用来验签)是核心,把这两个过程弄通了,其他的都不是事儿。那么如何配置密钥呢?还是参考 https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.dYvec2&treeId=64&articleId=104804&docType=1

下的接入准备->配置密钥对 这个介绍,简单的说就是从阿里提供的网站上下载密钥对生成工具 ,因为我采用的是rsa方式加密,所以我选择ras  1024 方式生成的密钥对(打开密钥对生成软件,选择好属性后,会生成两个配对的字符串,没什么技术含量),然后在网站上把密钥对填写进去就好了。


至此,第一阶段准备工作完毕。还是提醒大家,认真阅读https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.dYvec2&treeId=64&articleId=104804&docType=1 这个。上面的是基于阿里提供的开发文档的。另外说明一下:阿里提供的demo是md5的方式,现在一般都采用rsa方式,所以我选择了rsa方式。


第二阶段:向支付宝发起支付请求,首先,构造请求URL,下面是我构造出的最终的url,请参考,某些数据我已脱敏,请大家注意;

https://mapi.alipay.com/gateway.do?_input_charset=UTF-8&account_name=%E5%8C%97%E6%B1%BD%E7%A6%8F%E7%94%B0%E6%B1%BD%E8%BD%A6%E8%82%A1%E4%BB%BD%E6%9C%89%E9%99%90%E5%85%AC%E5%8F%B8%E5%8C%97%E4%BA%AC%E6%B1%BD%E8%BD%A6%E9%94%80%E5%94%AE%E5%88%86%E5%85%AC%E5%8F%B8&batch_fee=0.30&batch_no=24564564081299&batch_num=3&detail_data=24564563998192%5Ezh_haining%40163.com%5E%E8%B5%B5%E6%B5%B7%E5%AE%81%5E0.10%5E%E8%BD%A6%E4%B8%BB%E6%9C%89%E7%A4%BC%E6%89%B9%E9%87%8F%E4%BB%98%E6%AC%BE%E6%B5%8B%E8%AF%95zh_haining%7C24564564042634%5E694942199%40qq.com%5E%E5%BC%A0%E7%8C%9B%5E0.10%5E%E8%BD%A6%E4%B8%BB%E6%9C%89%E7%A4%BC%E6%89%B9%E9%87%8F%E4%BB%98%E6%AC%BE%E6%B5%8B%E8%AF%95zhangmeng%7C24564564059523%5E15652670315%5E%E5%88%9D%E5%BF%97%E5%BC%BA%5E0.10%5E%E8%BD%A6%E4%B8%BB%E6%9C%89%E7%A4%BC%E6%89%B9%E9%87%8F%E4%BB%98%E6%AC%BE%E6%B5%8B%E8%AF%95chuzhiqiang&email=jinyu2%40foton.com.cn¬ify_url=https%3A%2F%2Fczyl.foton.com.cn%2Falipay-classic-demo%2FAlipayNotifyServlet&partner=2088621258932563&pay_date=20170508&service=batch_trans_notify&sign=I3WpnIpLSUMegUpncUjRxDSWmbi5oJgcQKqx%2Bta8A5dG9*****dajEj%2Bw6GJFiQQlZioumggyJxAKC3AFjTV0OwHrGbmFG%2FhHfeMwjssSsicHN10Lf3aIHSyS5WECYB0FPLJsonroCAiWY%2FrAwdUzJR%2BK6iSw%3D&sign_type=RSA

将这个构造出的url放到IE浏览器下打开,就可以跳转到阿里支付宝提供的付款页面,其实就是输入密码完成支付的页面。

构造付款请求url的代码:

String signStr = "";
			
			/**去除参数中不需要参与签名的参数*/
			MapparamMap = AlipayUtil.paraFilter(AlipayConfig.alipayConfigMap);
			String preSignatureStr = AlipayUtil.createLinkString(paramMap,false);
			System.out.println("待签名字符串:"+preSignatureStr);
			try {
			    signStr = AlipaySignature.rsaSign(preSignatureStr, AlipayConfig.PRIVATE_KEY, (String)(AlipayConfig.alipayConfigMap.get("_input_charset")));
				System.out.println("参数签名后签名串为:"+signStr);
			} catch (AlipayApiException e) {
				System.err.println("数据签名失败,失败原因"+e.getMessage());
				e.printStackTrace();
			}
			AlipayConfig.alipayConfigMap.put("sign", signStr);
			String paramStr = AlipayUtil.createLinkString(AlipayConfig.alipayConfigMap,true);
			String url = AlipayConfig.GATEWAY+paramStr;
			System.out.println("构造的url为:"+url);


其中AlipayUtil.java 代码为:

package com.foton.cn.alipay.util;

import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

        List keys = new ArrayList(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 (flag) {
            	value = URLEncoder.encode(value);
			}
            if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
                prestr = prestr + key + "=" + value;
            } else {
                prestr = prestr + key + "=" + value + "&";
            }
        }

        return prestr;
    }
    
    /** 
     * 除去数组中的空值和签名参数
     * @param sArray 签名参数组
     * @return 去掉空值与非签名参数后的新签名参数组(其中参数[sign]和[sign_type]两个参数不参与签名)
     */
    public static Map paraFilter(Map sArray) {

        Map result = new HashMap();

        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;
    }
}

AlipayConfig.java(某些值已脱敏,请根据自己的填写) 代码:

package com.foton.cn.alipay.util;

import java.util.HashMap;
import java.util.Map;

public class AlipayConfig {
	
	/**支付宝公钥,非开发者公钥*/
	public final static String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBA*******";
	
	public final static String PRIVATE_KEY = "****DJez0***Cv0c=";
	public final static String GATEWAY = "https://mapi.alipay.com/gateway.do?";
	public final static String HTTPS_VERIFY_URL = "https://mapi.alipay.com/gateway.do?service=notify_verify&";//支付宝消息验证地址
	public final static String SIGN_TYPE = "RSA";//签名方式
	
	public static MapalipayConfigMap = new HashMap<>();
	
	static{
		alipayConfigMap.put("sign_type", "RSA");//签名方式
		alipayConfigMap.put("service", "batch_trans_notify");//接口名称
		alipayConfigMap.put("partner", "2088621***2563");//合作身份者ID
		alipayConfigMap.put("_input_charset", "UTF-8");//参数编码字符集
		alipayConfigMap.put("notify_url", "https://czyl.foton.com.cn/alipay-classic-demo/AlipayNotifyServlet");//服务器异步通知页面路径
		alipayConfigMap.put("account_name", "**公司");//付款账号名
		alipayConfigMap.put("detail_data", System.nanoTime()+"^zh_**[email protected]^赵*宁^0.10^测试zh**ning|"+System.nanoTime()+"^[email protected]^**猛^0.10^付款测|"+System.nanoTime()+"^15652670315^初^0.10^**批量付款测试");
		alipayConfigMap.put("batch_no", ""+System.nanoTime());//付款批次号
		alipayConfigMap.put("batch_num", "3");//付款总笔数
		alipayConfigMap.put("batch_fee", "0.30");//付款总金额
		alipayConfigMap.put("email", "[email protected]");//付款总金额
		alipayConfigMap.put("pay_date", "20170508");//付款日期
	}
}

AlipaySignature 这个是ali 提供的sdk包(alipay-sdk-java20170411150054.jar),直接下载加入jar包就行;下面附上程序运行控制台日志(请主要看格式及参数名,参数值我已做脱敏):

待签名字符串:_input_charset=UTF-8&account_name=***公司&batch_fee=0.30&batch_no=2929***90&batch_num=3&detail_data=29297811659726^zh**[email protected]^赵**^0.10^批量付款测试|292978117**58^[email protected]^张*^0.10^批量付款测试|29297**946^15652670315^*强^0.10^批量付款测试[email protected]¬ify_url=https://czyl.xnds.com.cn/alipay-classic-demo/AlipayNotifyServlet&partner=2088621***63&pay_date=20170508&service=batch_trans_notify
参数签名后签名串为:HpqmGye7LyZo27gQ0XGKAFImuOvdKPRuUM5s33zHjs3ldziS3g4tR5UPlP5AL11ipW2GWOJ4UYNJQnjTCY/BlLyc4HpHavB91j7sHUk8RjQcm5oQllseoPTb307PNf4NsMwftUniScR8WIEm7YDhoT9ePf3m60oN37gkDaBUOSI=
构造的url为:https://mapi.alipay.com/gateway.do?_input_charset=UTF-8&account_name=%E5%8C%97%E6%B1%BD%E7%A6%8F%E7%94%B0%E6%B1%BD%E8%BD%A6%E8%82%A1%E4%BB%BD%E6%9C%89%E9%99%90%E5%85%AC%E5%8F%B8%E5%8C%97%E4%BA%AC%E6%B1%BD%E8%BD%A6%E9%94%80%E5%94%AE%E5%88%86%E5%85%AC%E5%8F%B8&batch_fee=0.30&batch_no=292978**390&batch_num=3&detail_data=29297811659726%5Ezh_**ng%40126.com%5E%E8%B5%B5%E6%B5%B7%E5%AE%81%5E0.10%5E%E8%BD%A6%E4%B8%BB%E6%9C%89%E7%A4%BC%E6%89%B9%E9%87%8F%E4%BB%98%E6%AC%BE%E6%B5%8B%E8%AF%95zh_**ning%7C29297811709058%5E694942199%40126.com%5E%E5%BC%A0%E7%8C%9B%5E0.10%5E%E8%BD%A6%E4%B8%BB%E6%9C%89%E7%A4%BC%E6%89%B9%E9%87%8F%E4%BB%98%E6%AC%BE%E6%B5%8B%E8%AF%95%7C29297811725946%5E15652670315%5E%E5%88%9D%E5%BF%97%E5%BC%BA%5E0.10%5E%E8%BD%A6%E4%B8%BB%E6%9C%89%E7%A4%BC%E6%89%B9%E9%87%8F%E4%BB%98%E6%AC%BE%E6%B5%8B%E8%AF%95chuzhiqiang&email=jinyu2%40sdsf.com.cn¬ify_url=https%3A%2F%2Fczyl.dsff.com.cn%2Falipay-classic-demo%2FAlipayNotifyServlet&partner=208***563&pay_date=20170508&service=batch_trans_notify&sign=HpqmGye7LyZo27gQ0XGKAFImuOvdKPRuUM5s33zHjs3ldziS3g4tR5UPlP5AL11ipW2GWOJ4UYNJQnjTCY%2FBlLyc4HpHavB91j7sHUk8RjQcm5oQllseoPTb307PNf4NsMwftUniScR8WIEm7YDhoT9ePf3m60oN37gkDaBUOSI%3D&sign_type=RSA
https://mapi.alipay.com/gateway.do?_input_charset=UTF-8&account_name=%E5%8C%97%E6%B1%BD%E7%A6%8F%E7%94%B0%E6%B1%BD%E8%BD%A6%E8%82%A1%E4%BB%BD%E6%9C%89%E9%99%90%E5%85%AC%E5%8F%B8%E5%8C%97%E4%BA%AC%E6%B1%BD%E8%BD%A6%E9%94%80%E5%94%AE%E5%88%86%E5%85%AC%E5%8F%B8&batch_fee=0.30&batch_no=292978**390&batch_num=3&detail_data=29297811659726%5Ezh_**ng%40126.com%5E%E8%B5%B5%E6%B5%B7%E5%AE%81%5E0.10%5E%E8%BD%A6%E4%B8%BB%E6%9C%89%E7%A4%BC%E6%89%B9%E9%87%8F%E4%BB%98%E6%AC%BE%E6%B5%8B%E8%AF%95zh_**ning%7C29297811709058%5E694942199%40126.com%5E%E5%BC%A0%E7%8C%9B%5E0.10%5E%E8%BD%A6%E4%B8%BB%E6%9C%89%E7%A4%BC%E6%89%B9%E9%87%8F%E4%BB%98%E6%AC%BE%E6%B5%8B%E8%AF%95%7C29297811725946%5E15652670315%5E%E5%88%9D%E5%BF%97%E5%BC%BA%5E0.10%5E%E8%BD%A6%E4%B8%BB%E6%9C%89%E7%A4%BC%E6%89%B9%E9%87%8F%E4%BB%98%E6%AC%BE%E6%B5%8B%E8%AF%95chuzhiqiang&email=jinyu2%40sdsf.com.cn¬ify_url=https%3A%2F%2Fczyl.dsff.com.cn%2Falipay-classic-demo%2FAlipayNotifyServlet&partner=208***563&pay_date=20170508&service=batch_trans_notify&sign=HpqmGye7LyZo27gQ0XGKAFImuOvdKPRuUM5s33zHjs3ldziS3g4tR5UPlP5AL11ipW2GWOJ4UYNJQnjTCY%2FBlLyc4HpHavB91j7sHUk8RjQcm5oQllseoPTb307PNf4NsMwftUniScR8WIEm7YDhoT9ePf3m60oN37gkDaBUOSI%3D&sign_type=RSA

=====================结束


将构造的url用IE打开,直接跳入支付宝提供的页面,输入密码即可,所以这里有两个需要注意的,第一个,需要安装数字证书后才能正常使用,因为数字证书只支持IE浏览器,所以之前说为什么要用IE打开,就是这个原因,只有在IE上安装了数字证书,跳转到支付宝支付页面中才能加载出输入密码的框;数字证书安装方法请参考:https://110.alipay.com/cert/intro.htm   如果有问题,可以联系支付宝在线技术客服协助解决;第二个就是 需要公司提供支付密码(我们公司财务处于安全原因,迟迟不给开发提供支付宝支付密码,最后没办法影响到了工作进度,领导签下军令状之后才把支付密码告诉我,这里提醒一下,因为支付宝没有测试环境,每一笔支付都是对接支付宝的正式系统,所以支付密码是必须要有的,而且钱是真的转过去了,所以开发人员测试时一定要注意转账金额,我转账是转给我自己的,所以我不担心,大不了转错了我再转回给公司就行了)。


至此,第二阶段发起支付请求就完成了。我做的是异步通知,所以接下来就是处理异步反馈通知的。


第三阶段,支付宝异步通知接口,这个接口注意了,需要外网能够访问的,否则支付宝请求不到。我们只用nginx 通过生产外网域名转到我们内部服务器上的。在异步接口中做如下处理

       1、接受支付宝发送的结果,结果样例如下:

===================支付宝反馈参数=============
notify_time= 2017-05-08 10:52:39
notify_type= batch_trans_notify
notify_id= db0c291a9***7de07b36f4j5y
sign_type= RSA
sign= iPm2IRJwTEKe0celNK*****Ax8cLWBCX6XMSSok5+kMvkIhHphNaX5gtEIQhwZ1uFy0Cvrgo/Sy6lxw1lAc1GppTUDDNNTh2uIlJE=
batch_no= 326***722964
pay_user_id= 2088621*****2563
pay_user_name= ***公司
pay_account_no= 208862***30156
success_details= 326667874668162^zh***[email protected]^**宁^0.10^S^^201705080**6429^20170508***08|326667874696594^[email protected]^**猛^0.10^S^^201705080222916430^2017**05108|326**07995^1565**15^**强^0.10^S^^20170508***6431^201***5109|
fail_details= null
===================支付宝反馈参数=============

       2、验证结果真实性:包含:a.是否支付宝发送过来的数据;b.验签  这两步,这两不非常关键,我直接贴详细代码

这块我就直接上代码了:

/** 
	* TODO:验证消息是否是支付宝发出的合法消息
	* @param: 
	*		@param params
	*		@return boolean 验证结果
	* @author: [email protected]   @date: 2017年5月8日 下午02:09:23 
	*/
    public boolean verify(Map 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 = false;
		try {
			isSign = getSignVeryfy(params, sign);
		} catch (AlipayApiException e) {
			System.err.println("验证签名出现异常");
			e.printStackTrace();
		}
        if (isSign && responseTxt.equals("true")) {
            return true;
        } else {
            return false;
        }
    }
    
    /**
     * 根据反馈回来的信息,生成签名结果
     * @param resultDataMap 通知返回来的参数数组
     * @param sign 比对的签名结果
     * @return 生成的签名结果
     * @throws AlipayApiException 
     */
    public boolean getSignVeryfy(Map resultDataMap, String sign) throws AlipayApiException {
    	Map filterResultDataMap = AlipayUtil.paraFilter(resultDataMap);
    	filterResultDataMap.put("sign_type", AlipayConfig.SIGN_TYPE);
    	filterResultDataMap.put("sign", sign);
    	//获取待签名字符串
//        String preSignStr = AlipayUtil.createLinkString(filterResultDataMap,false);
    	
        boolean isSign = false;
        if(AlipayConfig.SIGN_TYPE.equals("RSA") ) {
        	isSign = AlipaySignature.rsaCheckV1(filterResultDataMap, AlipayConfig.PUBLIC_KEY, AlipayConfig.CHARSET);
        	log.debug("\n支付宝结果验签结果:"+isSign);
        }
        return isSign;
    }

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

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

        3、具体业务逻辑处理,这块根据收到的支付宝支付结果自行编写项目业务逻辑代码,我自己项目中就是收到支付宝结果后,把提现记录状态改为付款成功或者失败。


        4、反馈状态至支付宝,这一步很关键,是这样,支付宝异步发给我们支付结果,我们接收到处理完成之后,要给支付宝返回success或者fail 这两个字符串,否则,支付宝会认为发送支付结果失败,会不停的给我们系统发送支付结果(也即不停的触发我们反馈的异步结果的结果)这样就导致我们会不停的处理结果,这样是不合理的。首先支付宝官方给出的发送结果的的规则是:程序执行完后必须打印输出“success”(不包含引号)。如果商户反馈给支付宝的字符不是success这7个字符,支付宝服务器会不断重发通知,直到超过24小时22分钟。一般情况下,25小时以内完成8次通知(通知的间隔频率一般是:4m,10m,10m,1h,2h,6h,15h);

这里 我给出异步接口的代码,标红的部分即为返回支付宝的处理结果:

/**
	 * @TODO 支付宝异步通知接口:支付宝将支付结果异步发至系统
	 * @param request
	 * @param response
	 */
	@RequestMapping(value = "/alipayNotify")
	@ResponseBody
	public void alipayNotify(HttpServletRequest request, HttpServletResponse response){
		/**1、获取支付宝异步通知支付结果*/
		Map resultDataMap = alipayService.getPayResultMap(request);
		
		Log.debug("接收到支付宝参数【resultDataMap】为:"+resultDataMap);
		/**2、验证结果是否合法(a.是否支付宝发送过来的数据;b.验签)*/
		boolean vertifyResult = alipayService.verify(resultDataMap);
		resultDataMap.put("sign_result", vertifyResult+"");
		/**3、记录支付宝发送的支付结果流水日志*/
		List>recordDataList = alipayService.analysisPayDetail(resultDataMap);
		alipayService.saveAlipayRecord(resultDataMap,recordDataList);
		
		PrintWriter out = null;
		
		try {
			out = response.getWriter();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		if (!vertifyResult) {
			Log.info("您好,您收到一条非支付宝官方数据,在确保资金安全情况下,系统进行拦截并审核,给您带来不便请谅解[ERROR-1000:验证签名错误]");
			out.println("fail");
		}else{
			/**4、业务逻辑处理*/
			//a.更新APP系统数据库付款状态
			alipayService.updateAlipayResult(recordDataList);
			
			//b.发送xml报文至siebel和sap通知他们支付结果
			MapparamMap = alipayService.buildXmlMapData(recordDataList);
			System.out.println("发送esb的参数:"+paramMap);
			try {
				marketingWebService.foton_ESB_SIEBEL_017_Interface(paramMap);
				out.println("success");
			} catch (Exception e) {
				out.println("fail");
				e.printStackTrace();
			}
		}
		out.flush();
		out.close();
	}

至此,对接支付宝一个批次的付款完成了,如果朋友们想要完整的代码,请联系我[email protected],谢谢。


最后,我说一下我在对接支付宝过程中遇到的几个问题,希望对大家有帮助:

1、在签名时,有些参数是不参与签名的,比如,sign和sign_type  这两个参数,前提是在RSA加密方式下,官方给的md5方式和这个不一样,如果调试过成功老是提示签名非法什么的,解决方案有两个:a.确认自己参与签名的参数是否完整,这个也可以找阿里技术支持协助支持一下;b. 如果是RSA加密方式,在配置密钥时一定要选择1024长度的进行配置,我之前就是因为配置的2048,导致签名错误,这里强调,RSA只支持1024密钥长度。


2、浏览器问题,付款是需要用到数字证书,而数字证书只支持IE浏览器,所以项目需要在IE浏览器下运行。我在做的过成功遇到这样的情况,我们项目是兼容firefox和chrome的,但是就是不支持IE,我尝试用程序控制自动在chrome或者Firefox下强行打开IE浏览器,网上也查了什么IE tab插件,以及Java打开IE方式(这个在window本地可以打开,结果我部署到Linux测试环境上,傻眼了,根本不能达到目的)等等,最终都行不通,放弃了;后来我们前端专门对支付功能这块做了IE的兼容才解决这个问题。


3、验签:一定不能忘记这个环节,好多程序员以前没有做过支付功能,以为拿到支付结果就高兴的晕头转向了,想过没有,如果有人冒充给你发假信息,结果你程序还正常跑通了,这个后果你想过吗;所以验签(验证消息是否真实很重要),在这个过程中,我验签始终不成功,后来找阿里在线技术支持帮忙协助,最后发现参与验签的参数和key是错误的。


4、对接功能终于成功了,终于可以松口气了,但是就在这时,我发现一笔支付,支付宝不停的给我发结果,我付款也成功了,数据状态也改过来了,但是支付宝好像没收到我的结果(success 或者 fail),还是按照它的规则不停的给我退结果,找阿里在线技术支持,他帮我查了一下,说是Http 302 错误,我也是捣鼓了大半天,后台我恍然大悟,我们系统有安全拦截机制的,就是登录过滤器,也就是如果你没有登录,是不允许用户使用系统的,我把接口地址是给支付宝了,但是他访问我的项目的时候他没有登录,系统处理就会自动让跳转到登录页面,这样支付宝就会报错,即 http 302,解决方案:在登录拦截器中取消对异步通知接口的拦截,修改了这个,项目简直完美的西里啪啦的,不要不要的。






















你可能感兴趣的:(经典示例)