1.alipay 双功能支付简介

2.alipay 提交支付订单

3.alipay 整合双功能支付及发货信息同步

4.alipay 页面跳转同步通知处理

5.alipay 服务器异步通知处理

 

======================  华丽丽的分割线  ======================

 

1.alipay 双功能支付简介

 

1.0 L.z的唠叨

  网上copy的东西那么多,查个东西在百度上google一下都搜不到个完整,我恨!代码还是看自己整理的比较好。

 

1.1 使用流程

  在网站中生成订单信息,并记录到数据库中,将订单信息及其他必要信息按照alipayto指定的形式,发给支付宝,也就是生成完了调AlipayService.BuildForm() 方法,改方法会返回一串字符串,里面记录着表单信息,无需更改返回的字符串,并使之打印到页面上(该字符串有js写的自动提交表单)。

  此时进入支付宝付款页面,当支付成功时,支付宝会根据我们设置的returnURL来访问我们指定的页面(action),我们可以根据他回馈的状态及订单号,钱等信息进行对数据库相应处理(得判断状态是否一致)。

  但是,上述的情况只是在用户每关闭我们网站的时候才会出现,事实上,有可能用户在没付款结束时就关闭了网站。支付宝为解决这个问题,使用了notifyURL,即每次用户的交易状态发生更改,都会主动向notifyURL中设置的页面(action)发出通知,以便我们能设置商业逻辑。

  为此,需要编写或更改的,有如下:aAlipayConfig(设置alipay账户,及跳转通知页面等基本信息),alipayto(生成表单并提交),returnURL(页面跳转同步通知处理文件),notifyURL(服务器异步通知处理文件)。

  由于可能存在重复通知,所以必须忠实的判断订单的状态,以免重复操作。

 

1.2 支付宝双功能支付所需要的类

  所需要的类如下:

AlipayConfig.java

    这个类里面需要我去修改一些信息,如:身份ID,key等

AlipayService.java

    请求处理类,可整合进发货信息同步(当然,也可以独立出来,不过我感觉没那个必要)

AlipayNotify.java

    该类无需更改。

Md5Encrpt.java

    支付宝传输参数加密用,无需更改 

AlipayFunction.java

    公用函数,alipay 请求、通知时调用,无需更改

SetCharacterEncodingFilter.java

    字符串格式,无需更改(搞笑的是,里面的注释是英文的,与上面的类注释不同,不协调~~)

UtilDate.java

    自定义订单类,用于生成订单号,该类可要可不要(能确保自己生成的订单号唯一就行)

  (建议以上放在同一包中)

AlipayAction.java

    用于编写alipayTo(),notifyURL(),returnURL() 等处理alipay相关方法

  

  另外,还需要如下jsp页面:

alipayto.jsp

    用于跳转到打印AlipayService.BuildForm()返回的字符串,跳转到 alipay 的支付页面(当然,也可以改造成直接从Action中提交)

return_url.jsp

    用于展示用户订单支付成功的页面。 

 

======================  华丽丽的分割线  ======================

 

2.alipay 提交支付订单

  

2.1 设置AlipayConfig信息

  如前所述,签约支付的卖家帐号,服务器通知的页面,字符编码格式等,都在这里设置,如下:


1 /* *
 2  *功能:设置帐户有关信息及返回路径(基础配置页面)
 3  *版本:3.1
 4  *日期:2010-11-25
 5  *说明:
 6  *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
 7  *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
 8     
 9  *提示:如何获取安全校验码和合作身份者ID
10  *1.访问支付宝首页(www.alipay.com),然后用您的签约支付宝账号登陆.
11  *2.点击导航栏中的“商家服务”,即可查看
12     
13  *安全校验码查看时,输入支付密码后,页面呈灰色的现象,怎么办?
14  *解决方法:
15  *1、检查浏览器配置,不让浏览器做弹框屏蔽设置
16  *2、更换浏览器或电脑,重新登录查询。
17  * */
18 package com.blank.alipay;
19 
20 import java.util.*;
21 
22 public class AlipayConfig {
23     // 如何获取安全校验码和合作身份者ID
24     // 1.访问支付宝商户服务中心(b.alipay.com),然后用您的签约支付宝账号登陆.
25     // 2.访问“技术服务”→“下载技术集成文档”(https://b.alipay.com/support/helperApply.htm?action=selfIntegration)
26     // 3.在“自助集成帮助”中,点击“合作者身份(Partner ID)查询”、“安全校验码(Key)查询”
27     
28     //↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
29     // 合作身份者ID,以2088开头由16位纯数字组成的字符串
30     public static String partner = "";
31     
32     // 交易安全检验码,由数字和字母组成的32位字符串
33     public static String key = "";
34     
35     // 签约支付宝账号或卖家收款支付宝帐户
36     public static String seller_email = "";
37     
38     // notify_url 交易过程中服务器通知的页面 要用 http://格式的完整路径,不允许加?id=123这类自定义参数
39     public static String notify_url = "";
40     
41     // 付完款后跳转的页面 要用 http://格式的完整路径,不允许加?id=123这类自定义参数
42     public static String return_url = "";
43     
44     // 网站商品的展示地址,不允许加?id=123这类自定义参数
45     public static String show_url = "";
46     
47     //收款方名称,如:公司名称、网站名称、收款人姓名等
48     public static String mainname = "";
49     //↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
50 
51 
52     // 字符编码格式 目前支持 gbk 或 utf-8
53     // 这里注意要小写,我的alipay双功能支付文件中居然是大写(拿到手就这样),结果出现异常,如果你莫名奇妙的异常,请检查这里。很无语...
54     public static String input_charset = "utf-8";
55     
56     // 签名方式 不需修改
57     public static String sign_type = "MD5";
58     
59     //访问模式,根据自己的服务器是否支持ssl访问,若支持请选择https;若不支持请选择http
60     public static String transport = "http";
61 }


附注:我拿到alipay双功能支付的时候,里面AlipayConfig.java文件中,input_charset="UTF-8"。这让人很无语,只支持小写,可默认的却又大写。导致出现奇怪的异常...
 

2.2 提交支付订单的Action (AlipayAction.java)


1     /**
  2      * 要充值的金额
  3      */
  4     private String alimoney;
  5 
  6     /**
  7      * 要支付的订单编号
  8      */
  9     private String tradeNumber;
 10 
 11     /**
 12      * 生成的HTML-URL,需到JSP打印出来
 13      */
 14     private String sHtmlText;
 15 
 16     // Getter/Setter 方法略,若还需要其他信息同理。
 17 
 18     public String payTo() {
 19         boolean flag = true;
 20         // 商业逻辑判断,判断各种信息是否正确,如:金钱,用户信息等
 21         // ...略
 22 
 23         if(flag) {
 24             // 如若无误,写入数据库,并记录状态,生成订单,获取订单ID等信息。
 25             // ...略
 26 
 27             // 调用入口页方法
 28             alipayTo();
 29 
 30             // 跳转到打印sHtmlText页面
 31             return SUCCESS;
 32         }else {
 33             // 信息部正确,跳转到提示错误页面
 34             return INPUT;
 35         }
 36     }
 37 
 38 
 39     /**
 40      * 功能:设置商品有关信息(入口页) 详细:该页面是接口入口页面,生成支付时的URL
 41      */
 42     private void alipayTo() {
 43         String input_charset = AlipayConfig.input_charset;
 44         String sign_type = AlipayConfig.sign_type;
 45         String seller_email = AlipayConfig.seller_email;
 46         String partner = AlipayConfig.partner;
 47         String key = AlipayConfig.key;
 48 
 49         String show_url = AlipayConfig.show_url;
 50         String notify_url = AlipayConfig.notify_url;
 51         String return_url = AlipayConfig.return_url;
 52                     
 53         ///
 54         
 55         // 以下参数是需要通过下单时的订单数据传入进来获得
 56         // 必填参数
 57         
 58         ///
 59         // 这里是需要修改的,暂且注释掉
 60         // UtilDate date = new UtilDate();//调取支付宝工具类生成订单号
 61         // String out_trade_no = date.getOrderNum();//请与贵网站订单系统中的唯一订单号匹配
 62         String out_trade_no = tradeNumber;
 63 
 64         // 订单名称,显示在支付宝收银台里的“商品名称”里,显示在支付宝的交易管理的“商品名称”的列表里。
 65         // String subject = new String(request.getParameter("aliorder").getBytes("ISO-8859-1"),"utf-8");
 66         String subject = "XX网站充值" + alimoney + "元货币";
 67 
 68         // 订单描述、订单详细、订单备注,显示在支付宝收银台里的“商品描述”里
 69         // String body = new String(request.getParameter("alibody").getBytes("ISO-8859-1"),"utf-8");
 70         String body = "default";
 71 
 72         // 订单总金额,显示在支付宝收银台里的“应付总额”里
 73         // String price = new String(request.getParameter("alimoney").getBytes("ISO-8859-1"),"utf-8");
 74         String price = alimoney;
 75 
 76         String logistics_fee = "0.00";                // 物流费用,即运费。
 77         String logistics_type = "EXPRESS";            // 物流类型,三个值可选:EXPRESS(快递)、POST(平邮)、EMS(EMS)
 78         String logistics_payment = "SELLER_PAY";    // 物流支付方式,两个值可选:SELLER_PAY(卖家承担运费)、BUYER_PAY(买家承担运费)
 79 
 80         String quantity = "1";                        // 商品数量,建议默认为1,不改变值,把一次交易看成是一次下订单而非购买一件商品。
 81 
 82         // 扩展参数——买家收货信息(推荐作为必填)
 83         // 该功能作用在于买家已经在商户网站的下单流程中填过一次收货信息,而不需要买家在支付宝的付款流程中再次填写收货信息。
 84         // 若要使用该功能,请至少保证receive_name、receive_address有值
 85         String receive_name    = "收货人姓名";            // 收货人姓名,如:张三
 86         String receive_address = "收货人地址";        // 收货人地址,如:XX省XXX市XXX区XXX路XXX小区XXX栋XXX单元XXX号
 87         String receive_zip = "123456";                // 收货人邮编,如:123456
 88         String receive_phone = "0571-81234567";        // 收货人电话号码,如:0571-81234567
 89         String receive_mobile = "13312341234";        // 收货人手机号码,如:13312341234
 90 
 91         //扩展参数——第二组物流方式
 92         //物流方式是三个为一组成组出现。若要使用,三个参数都需要填上数据;若不使用,三个参数都需要为空
 93         //有了第一组物流方式,才能有第二组物流方式,且不能与第一个物流方式中的物流类型相同,
 94         //即logistics_type="EXPRESS",那么logistics_type_1就必须在剩下的两个值(POST、EMS)中选择
 95         String logistics_fee_1 = "";                // 物流费用,即运费。
 96         String logistics_type_1    = "";                // 物流类型,三个值可选:EXPRESS(快递)、POST(平邮)、EMS(EMS)
 97         String logistics_payment_1 = "";            // 物流支付方式,两个值可选:SELLER_PAY(卖家承担运费)、BUYER_PAY(买家承担运费)
 98 
 99         //扩展参数——第三组物流方式
100         //物流方式是三个为一组成组出现。若要使用,三个参数都需要填上数据;若不使用,三个参数都需要为空
101         //有了第一组物流方式和第二组物流方式,才能有第三组物流方式,且不能与第一组物流方式和第二组物流方式中的物流类型相同,
102         //即logistics_type="EXPRESS"、logistics_type_1="EMS",那么logistics_type_2就只能选择"POST"
103         String logistics_fee_2 = "";                // 物流费用,即运费。
104         String logistics_type_2    = "";                // 物流类型,三个值可选:EXPRESS(快递)、POST(平邮)、EMS(EMS)
105         String logistics_payment_2 = "";            // 物流支付方式,两个值可选:SELLER_PAY(卖家承担运费)、BUYER_PAY(买家承担运费)
106 
107         //扩展功能参数——其他
108         String buyer_email = "";                    // 默认买家支付宝账号
109         String discount = "";                        // 折扣,是具体的金额,而不是百分比。若要使用打折,请使用负数,并保证小数点最多两位数
110 
111         /
112 
113         构造函数,生成请求URL
114         sHtmlText = AlipayService.BuildForm(partner,seller_email,return_url,notify_url,show_url,out_trade_no,
115                  subject,body,price,logistics_fee,logistics_type,logistics_payment,quantity,receive_name,receive_address,
116                  receive_zip,receive_phone,receive_mobile,logistics_fee_1,logistics_type_1,logistics_payment_1,
117                  logistics_fee_2,logistics_type_2,logistics_payment_2,buyer_email,discount,input_charset,key,sign_type);
118     }


 

2.3 跳转到alipay支付页面(alipayto.jsp)


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>数据传输中...</title>
</head>

<body>
<div>
<!-- escape 用于设置是否编码,若为true会将内容(如:空格会被转成 )进行转换,建议设置成false,事实上,设置成true麻烦事更多 -->
<s:property value="sHtmlText" escape="false"/> 
</div>      
</body>
</html>


 

2.4 设置struts配置文件 (struts.xml)


<!-- 上部分,略 -->
<action name="payTo" class="AlipayAction" method="payTo">
<result name="success">alipayto.jsp</result>
<result name="input">exception.jsp</result>
</action>


 

======================  华丽丽的分割线  ======================

 

3.alipay 整合双功能支付及发货信息同步

 

3.1 交易通知

  在担保交易中,有如下的通知状态:WAIT_BUYER_PAY(等待买家付款)→WAIT_SELLER_SEND_GOODS(买家已付款,等待卖家发货)→WAIT_BUYER_CONFIRM_GOODS(卖家已发货,等待买家收货)→TRADE_FINISHED(买家已收货,交易完成)

  (在使用alipay做本次项目时,没涉及到退货环节,故不写上)

  由于alipay有这个WAIT_BUYER_CONFIRM_GOODS(卖家已发货,等待买家收货)状态存在,故在买家已付款的时候,我们需通知alipay,告知我们已发货,故需要在双功能支付的基础上整合进发货信息同步(其实也就2个方法),放在AlipayService.java中。

 

3.2 整合发货信息同步


1 import java.io.BufferedReader;
  2 import java.io.InputStreamReader;
  3 import java.io.OutputStream;
  4 import java.io.UnsupportedEncodingException;
  5 import java.net.HttpURLConnection;
  6 import java.net.URL;
  7 import java.net.URLEncoder;
  8 import java.util.ArrayList;
  9 import java.util.Collections;
 10 import java.util.HashMap;
 11 import java.util.List;
 12 import java.util.Map;
 13 
 14 
 15 /**
 16  *类名:alipay_service
 17  *功能:支付宝外部服务接口控制
 18  *详细:该页面是请求参数核心处理文件,不需要修改
 19  *版本:3.1
 20  *修改日期:2010-11-24
 21  *说明:
 22   以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
 23   该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
 24  */
 25 
 26 public class AlipayService {
 27     /**
 28      * 功能:构造表单提交HTML
 29      * @param partner 合作身份者ID
 30      * @param seller_email 签约支付宝账号或卖家支付宝帐户
 31      * @param return_url 付完款后跳转的页面 要用 以http开头格式的完整路径,不允许加?id=123这类自定义参数
 32      * @param notify_url 交易过程中服务器通知的页面 要用 以http开格式的完整路径,不允许加?id=123这类自定义参数
 33      * @param show_url 网站商品的展示地址,不允许加?id=123这类自定义参数
 34      * @param out_trade_no 请与贵网站订单系统中的唯一订单号匹配
 35      * @param subject 订单名称,显示在支付宝收银台里的“商品名称”里,显示在支付宝的交易管理的“商品名称”的列表里。
 36      * @param body 订单描述、订单详细、订单备注,显示在支付宝收银台里的“商品描述”里
 37      * @param price 订单总金额,显示在支付宝收银台里的“商品单价”里
 38      * @param logistics_fee 物流费用,即运费。
 39      * @param logistics_type 物流类型,三个值可选:EXPRESS(快递)、POST(平邮)、EMS(EMS)
 40      * @param logistics_payment 物流支付方式,两个值可选:SELLER_PAY(卖家承担运费)、BUYER_PAY(买家承担运费)
 41      * @param quantity 商品数量,建议默认为1,不改变值,把一次交易看成是一次下订单而非购买一件商品。
 42      * @param receive_name 收货人姓名,如:张三
 43      * @param receive_address 收货人地址,如:XX省XXX市XXX区XXX路XXX小区XXX栋XXX单元XXX号
 44      * @param receive_zip 收货人邮编,如:123456
 45      * @param receive_phone 收货人电话号码,如:0571-81234567
 46      * @param receive_mobile 收货人手机号码,如:13312341234
 47      * @param logistics_fee_1 第二组物流费用,即运费。
 48      * @param logistics_type_1 第二组物流类型,三个值可选:EXPRESS(快递)、POST(平邮)、EMS(EMS)
 49      * @param logistics_payment_1 第二组物流支付方式,两个值可选:SELLER_PAY(卖家承担运费)、BUYER_PAY(买家承担运费)
 50      * @param logistics_fee_2 第三组物流费用,即运费。
 51      * @param logistics_type_2 第三组物流类型,三个值可选:EXPRESS(快递)、POST(平邮)、EMS(EMS)
 52      * @param logistics_payment_2 第三组物流支付方式,两个值可选:SELLER_PAY(卖家承担运费)、BUYER_PAY(买家承担运费)
 53      * @param buyer_email 默认买家支付宝账号
 54      * @param discount 折扣,是具体的金额,而不是百分比。若要使用打折,请使用负数,并保证小数点最多两位数
 55      * @param input_charset 字符编码格式 目前支持 GBK 或 utf-8
 56      * @param key 安全校验码
 57      * @param sign_type 签名方式 不需修改
 58      * @return 表单提交HTML文本
 59      */
 60     public static String BuildForm(String partner,
 61             String seller_email,
 62             String return_url,
 63             String notify_url,
 64             String show_url,
 65             String out_trade_no,
 66             String subject,
 67             String body,
 68             String price,
 69             String logistics_fee,
 70             String logistics_type,
 71             String logistics_payment,
 72             String quantity,
 73             String receive_name,
 74             String receive_address,
 75             String receive_zip,
 76             String receive_phone,
 77             String receive_mobile,
 78             String logistics_fee_1,
 79             String logistics_type_1,
 80             String logistics_payment_1,
 81             String logistics_fee_2,
 82             String logistics_type_2,
 83             String logistics_payment_2,
 84             String buyer_email,
 85             String discount,
 86             String input_charset,
 87             String key,
 88             String sign_type){
 89         Map sPara = new HashMap();
 90         sPara.put("service","trade_create_by_buyer");
 91         sPara.put("payment_type","1");
 92         sPara.put("partner", partner);
 93         sPara.put("seller_email", seller_email);
 94         sPara.put("return_url", return_url);
 95         sPara.put("notify_url", notify_url);
 96         sPara.put("_input_charset", input_charset);
 97         sPara.put("show_url", show_url);
 98         sPara.put("out_trade_no", out_trade_no);
 99         sPara.put("subject", subject);
100         sPara.put("body", body);
101         sPara.put("price", price);
102         sPara.put("logistics_fee", logistics_fee);
103         sPara.put("logistics_type", logistics_type);
104         sPara.put("logistics_payment", logistics_payment);
105         sPara.put("quantity", quantity);
106         sPara.put("receive_name", receive_name);
107         sPara.put("receive_address", receive_address);
108         sPara.put("receive_zip", receive_zip);
109         sPara.put("receive_phone", receive_phone);
110         sPara.put("receive_mobile", receive_mobile);
111         sPara.put("logistics_fee_1", logistics_fee_1);
112         sPara.put("logistics_type_1", logistics_type_1);
113         sPara.put("logistics_payment_1", logistics_payment_1);
114         sPara.put("logistics_fee_2", logistics_fee_2);
115         sPara.put("logistics_type_2", logistics_type_2);
116         sPara.put("logistics_payment_2", logistics_payment_2);
117         sPara.put("buyer_email", buyer_email);
118         sPara.put("discount", discount);
119         
120         Map sParaNew = AlipayFunction.ParaFilter(sPara); //除去数组中的空值和签名参数
121         String mysign = AlipayFunction.BuildMysign(sParaNew, key);//生成签名结果
122         
123         StringBuffer sbHtml = new StringBuffer();
124         List keys = new ArrayList(sParaNew.keySet());
125         String gateway = "https://www.alipay.com/cooperate/gateway.do?";
126         
127         //GET方式传递
128         sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\" action=\"" + gateway + "_input_charset=" + input_charset + "\" method=\"get\">");
129         //POST方式传递(GET与POST二必选一)
130         //sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\" action=\"" + gateway + "_input_charset=" + input_charset + "\" method=\"post\">");
131         
132         for (int i = 0; i < keys.size(); i++) {
133             String name = (String) keys.get(i);
134             String value = (String) sParaNew.get(name);
135             
136             sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>");
137         }
138         sbHtml.append("<input type=\"hidden\" name=\"sign\" value=\"" + mysign + "\"/>");
139         sbHtml.append("<input type=\"hidden\" name=\"sign_type\" value=\"" + sign_type + "\"/>");
140         
141         //submit按钮控件请不要含有name属性
142         //sbHtml.append("<input type=\"submit\" value=\"支付宝确认付款\"></form>");
143         
144         sbHtml.append("<script>document.forms['alipaysubmit'].submit();</script>");
145         return sbHtml.toString();
146     }
147     
148     // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 整合Alipay发货信息同步 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
149     /** 
150      * 功能:把数组所有元素按照“参数=参数值”的模式用“&”字符拼接成字符串
151      * @param params 需要排序并参与字符拼接的参数组
152      * @param input_charset 编码格式
153      * @return 拼接后字符串
154      */
155     public static String CreateLinkString_urlencode(Map params, String input_charset){
156         List keys = new ArrayList(params.keySet());
157         Collections.sort(keys);
158 
159         String prestr = "";
160 
161         for (int i = 0; i < keys.size(); i++) {
162             String key = (String) keys.get(i);
163             String value = (String) params.get(key);
164 
165             try {
166                 prestr = prestr + key + "=" + URLEncoder.encode(value,input_charset) + "&";
167             } catch (UnsupportedEncodingException e) {
168 
169                 e.printStackTrace();
170             }
171         }
172 
173         return prestr;
174     }
175     
176     /**
177      * 功能:远程xml解析
178      * @param partner 合作身份者ID
179      * @param trade_no 支付宝交易号。它是登陆支付宝网站在交易管理中查询得到,一般以8位日期开头的纯数字(如:20100419XXXXXXXXXX)
180      * @param logistics_name 物流公司名称
181      * @param invoice_no 物流发货单号
182      * @param transport_type 物流发货时的运输类型,三个值可选:POST(平邮)、EXPRESS(快递)、EMS(EMS)
183      * @param seller_ip 卖家本地电脑IP地址
184      * @param input_charset 字符编码格式 目前支持 GBK 或 utf-8
185      * @param key 安全校验码
186      * @param sign_type 签名方式 不需修改
187      * @return 获得解析结果
188      */
189     public static String PostXml(String partner,
190             String trade_no,
191             String logistics_name,
192             String invoice_no,
193             String transport_type,
194             String seller_ip,
195             String input_charset,
196             String key,
197             String sign_type) throws Exception{
198         Map sPara = new HashMap();
199         sPara.put("service","send_goods_confirm_by_platform");
200         sPara.put("partner", partner);
201         sPara.put("trade_no", trade_no);
202         sPara.put("logistics_name", logistics_name);
203         sPara.put("invoice_no", invoice_no);
204         sPara.put("transport_type", transport_type);
205         sPara.put("seller_ip", seller_ip);
206         sPara.put("_input_charset", input_charset);
207         
208         Map sParaNew = AlipayFunction.ParaFilter(sPara); //除去数组中的空值和签名参数
209         String mysign = AlipayFunction.BuildMysign(sParaNew, key);//生成签名结果
210         
211         sParaNew.put("sign", mysign);
212         sParaNew.put("sign_type", "MD5");
213         
214         String strUrl = "https://www.alipay.com/cooperate/gateway.do?_input_charset=utf-8";
215         URL url = new URL(strUrl);
216         HttpURLConnection conn = (HttpURLConnection)url.openConnection();
217         conn.setRequestMethod("POST");
218         conn.setDoInput(true);
219         conn.setDoOutput(true);
220         OutputStream os = conn.getOutputStream();
221         os.write(CreateLinkString_urlencode(sParaNew,input_charset).getBytes("utf-8"));
222         os.close();
223 
224         BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
225         String line;
226         String xmlResult ="";
227         while( (line =br.readLine()) != null ){
228             xmlResult += "\n"+line;
229         }
230         br.close();
231 
232         return xmlResult;
233     }
234 }


 

======================  华丽丽的分割线  ======================

 

4.alipay 页面跳转同步通知处理

 

4.1 页面跳转同步通知

  当买家完成了支付流程后,会出现成功支付的页面,该页面做短暂停留后,会跳转到我们AlipayConfig.xml中的 return_url 属性所指定的页面,这称为页面跳转同步通知。

  我们需要在该页面请求中,做相应的商业逻辑处理,如判断并更改订单状态,增加数据库中表示money的字段,注意:判断状态是十分必要的,避免重复进行操作。

 

4.2 returnURL


1     /**
  2      * 功能:付完款后跳转的页面(页面跳转同步通知页面)
  3      * WAIT_SELLER_SEND_GOODS(表示买家已在支付宝交易管理中产生了交易记录且付款成功,但卖家没有发货);
  4      * TRADE_FINISHED(表示买家已经确认收货,这笔交易完成);
  5      * 
  6      * @return
  7      */
  8     public String returnURL() {
  9         String key = AlipayConfig.key;
 10         // 获取支付宝GET过来反馈信息
 11         Map params = new HashMap();
 12         
 13         // MyServletContext 为自定义的类,可无视,换成如下写法:
 14         // HttpServletRequet request = ServletActionContext.getRequest();
 15         HttpServletRequest request = MyServletContext.getRequest();
 16         
 17         Map requestParams = request.getParameterMap();
 18         for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
 19             String name = (String) iter.next();
 20             String[] values = (String[]) requestParams.get(name);
 21             String valueStr = "";
 22             for (int i = 0; i < values.length; i++) {
 23                 valueStr = (i == values.length - 1) ? valueStr + values[i]
 24                         : valueStr + values[i] + ",";
 25             }
 26             // 乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
 27             try {
 28                 valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
 29             } catch (UnsupportedEncodingException e) {
 30                 e.printStackTrace();
 31             }
 32             params.put(name, valueStr);
 33         }
 34 
 35         // 判断responsetTxt是否为ture,生成的签名结果mysign与获得的签名结果sign是否一致
 36         // responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
 37         // mysign与sign不等,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
 38         String mysign = AlipayNotify.GetMysign(params, key);
 39         String responseTxt = AlipayNotify.Verify(request
 40                 .getParameter("notify_id"));
 41         String sign = request.getParameter("sign");
 42 
 43         // 写日志记录(若要调试,请取消下面两行注释)
 44         // String sWord = "responseTxt=" + responseTxt +
 45         // "\n return_url_log:sign=" + sign + "&mysign=" + mysign +
 46         // "\n return回来的参数:" + AlipayFunction.CreateLinkString(params);
 47         // AlipayFunction.LogResult(sWord);
 48 
 49         // 获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
 50         String trade_no = request.getParameter("trade_no"); // 支付宝交易号
 51         String order_no = request.getParameter("out_trade_no"); // 获取订单号
 52         String total_fee = request.getParameter("price"); // 获取总金额
 53         String subject = "";
 54         try {
 55             subject = new String(request.getParameter("subject").getBytes(
 56                         "ISO-8859-1"), "UTF-8");
 57         } catch (UnsupportedEncodingException e1) {
 58             // TODO Auto-generated catch block
 59             e1.printStackTrace();
 60         }// 商品名称、订单名称
 61         
 62         String body = "";
 63         if (request.getParameter("body") != null) {
 64             try {
 65                 body = new String(request.getParameter("body").getBytes(
 66                         "ISO-8859-1"), "UTF-8");
 67             } catch (UnsupportedEncodingException e) {
 68                 e.printStackTrace();
 69             }// 商品描述、订单备注、描述
 70         }
 71         String buyer_email = request.getParameter("buyer_email"); // 买家支付宝账号
 72         String receive_name = "";// 收货人姓名
 73         if (request.getParameter("receive_name") != null) {
 74             try {
 75                 receive_name = new String(request.getParameter("receive_name")
 76                         .getBytes("ISO-8859-1"), "UTF-8");
 77             } catch (UnsupportedEncodingException e) {
 78                 e.printStackTrace();
 79             }
 80         }
 81         String receive_address = "";// 收货人地址
 82         if (request.getParameter("receive_address") != null) {
 83             try {
 84                 receive_address = new String(request.getParameter(
 85                         "receive_address").getBytes("ISO-8859-1"), "UTF-8");
 86             } catch (UnsupportedEncodingException e) {
 87                 e.printStackTrace();
 88             }
 89         }
 90         String receive_zip = "";// 收货人邮编
 91         if (request.getParameter("receive_zip") != null) {
 92             try {
 93                 receive_zip = new String(request.getParameter("receive_zip")
 94                         .getBytes("ISO-8859-1"), "UTF-8");
 95             } catch (UnsupportedEncodingException e) {
 96                 e.printStackTrace();
 97             }
 98         }
 99         String receive_phone = "";// 收货人电话
100         if (request.getParameter("receive_phone") != null) {
101             try {
102                 receive_phone = new String(request
103                         .getParameter("receive_phone").getBytes("ISO-8859-1"),
104                         "UTF-8");
105             } catch (UnsupportedEncodingException e) {
106                 // TODO Auto-generated catch block
107                 e.printStackTrace();
108             }
109         }
110         String receive_mobile = "";// 收货人手机
111         if (request.getParameter("receive_mobile") != null) {
112             try {
113                 receive_mobile = new String(request.getParameter(
114                         "receive_mobile").getBytes("ISO-8859-1"), "UTF-8");
115             } catch (UnsupportedEncodingException e) {
116                 e.printStackTrace();
117             }
118         }
119         String trade_status = request.getParameter("trade_status"); // 交易状态
120         // 获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
121 
122         String verifyStatus = "";
123         if (mysign.equals(sign) && responseTxt.equals("true")) {
124             // 
125             // 请在这里加上商户的业务逻辑程序代码
126 
127             // ——请根据您的业务逻辑来编写程序(以下代码仅作参考)——
128             if (trade_status.equals("WAIT_SELLER_SEND_GOODS")) {
129                 // 判断该笔订单是否在商户网站中已经做过处理(可参考“集成教程”中“3.4返回数据处理”)
130                 // 如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
131                 // 如果有做过处理,不执行商户的业务程序
132 
133 //                if ("WAIT_BUYER_PAY".equals(memberMoney.getRemark())
134 //                        && mMoney == Double.parseDouble(total_fee)) {
135 //                    memberMoney.setRemark("WAIT_BUYER_CONFIRM_GOODS");
136 //                    memberMoneyService.saveOrUpdate(memberMoney);
137 //                    Members member = memberService.get(mid);
138 //                    if(member.getIdealMoney()==null){ // 这里是前人的数据库设置不合理,没给金钱这字段默认值,故判断其是否为空
139 //                        member.setIdealMoney(mMoney);
140 //                    }else{
141 //                        member.setIdealMoney(member.getIdealMoney() + mMoney);
142 //                    }
143 //                    memberService.saveOrUpdate(member); // 如果订单状态为默认状态,则添加金钱
144 //                }
145 //                try {
146 //                    // 这里是发货信息同步
147 //                    String xmlResult = AlipayService.PostXml(
148 //                            AlipayConfig.partner, trade_no, "直接充值",
149 //                            "请到个人中心-我的钱包查看充值货币", "EXPRESS", "",
150 //                            AlipayConfig.input_charset, AlipayConfig.key,
151 //                            AlipayConfig.sign_type);
152 //                } catch (Exception e) {
153 //                    e.printStackTrace();
154 //                }
155 
156             }
157 
158             // ——请根据您的业务逻辑来编写程序(以下代码仅作参考)——
159             if (trade_status.equals("TRADE_FINISHED")) {
160                 // 判断该笔订单是否在商户网站中已经做过处理(可参考“集成教程”中“3.4返回数据处理”)
161                 // 如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
162                 // 如果有做过处理,不执行商户的业务程序
163                 
164 //                if ("WAIT_BUYER_PAY".equals(memberMoney.getRemark())
165 //                        && mMoney == Double.parseDouble(total_fee)) {
166 //                    memberMoney.setRemark("TRADE_FINISHED");
167 //                    memberMoneyService.saveOrUpdate(memberMoney);
168 //                    Members member = memberService.get(mid);
169 //                    if(member.getIdealMoney()==null){
170 //                        member.setIdealMoney(mMoney);
171 //                    }else{
172 //                        member.setIdealMoney(member.getIdealMoney() + mMoney);
173 //                    }
174 //                    memberService.saveOrUpdate(member); // 如果订单状态为默认状态,则添加金钱
175 //
176 //                    try {
177 //                        // 这里是发货信息同步
178 
179 //                        String xmlResult = AlipayService.PostXml(
180 //                                AlipayConfig.partner, trade_no, "直接充值",
181 //                                "个人中心请查看充值货币", "EXPRESS", "",
182 //                                AlipayConfig.input_charset, AlipayConfig.key,
183 //                                AlipayConfig.sign_type);
184 //                    } catch (Exception e) {
185 //                        e.printStackTrace();
186 //                    }
187 //                } else if ("WAIT_BUYER_CONFIRM_GOODS".equals(memberMoney
188 //                        .getRemark())
189 //                        && mMoney == Double.parseDouble(total_fee)) {
190 //                    memberMoney.setRemark("TRADE_FINISHED");
191 //                    memberMoneyService.saveOrUpdate(memberMoney);
192 //                }
193 //
194             }
195 
196             verifyStatus = "验证成功";
197             // ——请根据您的业务逻辑来编写程序(以上代码仅作参考)——
198 
199             // 
200         } else {
201             verifyStatus = "验证失败";
202         }
203         return SUCCESS;
204     }


 

4.3 struts.xml


1     <!-- 上面略,该action用于页面跳转同步通知 -->
2     <action name="payMoney" class="AlipayAction" method="payMoney">
3         <result name="success">alipayto.jsp</result>
4         <result name="input">exception.jsp</result>
5     </action>


 

======================  华丽丽的分割线  ======================

 

5.alipay 服务器异步通知处理

 

5.1 服务器异步通知

  买家在支付宝中完成交易,付了款后,会出现如下页面:

 


支付宝电脑付款 java 支付宝支付java_express

 

  该页面做数秒停留后,会跳转到 AlipayConfig.xml 中的 return_url 属性所指定的页面,这称为页面跳转同步通知(如前所述),而商业网站便在被调用的页面中,做业务逻辑处理。

  但是,买家可能在 Alipay 尚未跳转前,便把上面那页面关闭,这时怎么办?

  为解决这问题 ,支付宝便有了服务器异步通知。即每当交易状态发生变化,Alipay 都会主动通知AlipayConfig.xml 中的 notify_url 属性所指定的页面(该action不能有返回值,也不能跳转)。这样做确实解决了该问题,但也带来了可能重复调用,故,我们需要判断alipay传过来的状态是否被处理过,若处理过,则不重复执行。

 

5.2 notifyURL

逻辑处理语句略!!!


1     /**
  2      * 功能:支付宝主动通知调用的页面(服务器异步通知页面)
  3      * 
  4      * @return
  5      */
  6     public void notifyURL() {
  7         String key = AlipayConfig.key;
  8         // 获取支付宝POST过来反馈信息
  9         Map params = new HashMap();
 10         //HttpServletRequest request = ServletActionContext.getRequest();
 11         HttpServletRequest request = MyServletContext.getRequest();
 12         PrintWriter out = null;
 13         try {
 14             // out = ServletActionContext.getResponse().getWriter();
 15             out = MyServletContext.getResponse().getWriter();
 16         } catch (IOException e) {
 17             e.printStackTrace();
 18         }
 19         Map requestParams = request.getParameterMap();
 20         for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
 21             String name = (String) iter.next();
 22             String[] values = (String[]) requestParams.get(name);
 23             String valueStr = "";
 24             for (int i = 0; i < values.length; i++) {
 25                 valueStr = (i == values.length - 1) ? valueStr + values[i]
 26                         : valueStr + values[i] + ",";
 27             }
 28             // 乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
 29             // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
 30             params.put(name, valueStr);
 31         }
 32 
 33         // 判断responsetTxt是否为ture,生成的签名结果mysign与获得的签名结果sign是否一致
 34         // responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
 35         // mysign与sign不等,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
 36         String mysign = AlipayNotify.GetMysign(params, key);
 37         String responseTxt = AlipayNotify.Verify(request
 38                 .getParameter("notify_id"));
 39         String sign = request.getParameter("sign");
 40 
 41         // 写日志记录(若要调试,请取消下面两行注释)
 42         String sWord = "responseTxt=" + responseTxt + "\n notify_url_log:sign="
 43                 + sign + "&mysign=" + mysign + "\n notify回来的参数:"
 44                 + AlipayFunction.CreateLinkString(params);
 45         AlipayFunction.LogResult(sWord);
 46 
 47         // 获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
 48         String trade_no = request.getParameter("trade_no"); // 支付宝交易号
 49         String order_no = request.getParameter("out_trade_no"); // 获取订单号
 50         String total_fee = request.getParameter("price"); // 获取总金额
 51         String subject = "";
 52         try {
 53             subject = new String(request.getParameter("subject").getBytes(
 54                     "ISO-8859-1"), "UTF-8");
 55         } catch (UnsupportedEncodingException e) {
 56             e.printStackTrace();
 57         }// 商品名称、订单名称
 58         String body = "";
 59         if (request.getParameter("body") != null) {
 60             try {
 61                 body = new String(request.getParameter("body").getBytes(
 62                         "ISO-8859-1"), "UTF-8");
 63             } catch (UnsupportedEncodingException e) {
 64                 e.printStackTrace();
 65             }// 商品描述、订单备注、描述
 66         }
 67         String buyer_email = request.getParameter("buyer_email"); // 买家支付宝账号
 68         String receive_name = "";// 收货人姓名
 69         if (request.getParameter("receive_name") != null) {
 70             try {
 71                 receive_name = new String(request.getParameter("receive_name")
 72                         .getBytes("ISO-8859-1"), "UTF-8");
 73             } catch (UnsupportedEncodingException e) {
 74                 e.printStackTrace();
 75             }
 76         }
 77         String receive_address = "";// 收货人地址
 78         if (request.getParameter("receive_address") != null) {
 79             try {
 80                 receive_address = new String(request.getParameter(
 81                         "receive_address").getBytes("ISO-8859-1"), "UTF-8");
 82             } catch (UnsupportedEncodingException e) {
 83                 e.printStackTrace();
 84             }
 85         }
 86         String receive_zip = "";// 收货人邮编
 87         if (request.getParameter("receive_zip") != null) {
 88             try {
 89                 receive_zip = new String(request.getParameter("receive_zip")
 90                         .getBytes("ISO-8859-1"), "UTF-8");
 91             } catch (UnsupportedEncodingException e) {
 92                 e.printStackTrace();
 93             }
 94         }
 95         String receive_phone = "";// 收货人电话
 96         if (request.getParameter("receive_phone") != null) {
 97             try {
 98                 receive_phone = new String(request
 99                         .getParameter("receive_phone").getBytes("ISO-8859-1"),
100                         "UTF-8");
101             } catch (UnsupportedEncodingException e) {
102                 e.printStackTrace();
103             }
104         }
105         String receive_mobile = "";// 收货人手机
106         if (request.getParameter("receive_mobile") != null) {
107             try {
108                 receive_mobile = new String(request.getParameter(
109                         "receive_mobile").getBytes("ISO-8859-1"), "UTF-8");
110             } catch (UnsupportedEncodingException e) {
111                 e.printStackTrace();
112             }
113         }
114         String trade_status = request.getParameter("trade_status"); // 交易状态
115         // 获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
116 
117         if (mysign.equals(sign) && responseTxt.equals("true")) {// 验证成功
118             // 
119             // 请在这里加上商户的业务逻辑程序代码
120             
121             
122             // —— 请根据您的业务逻辑来编写程序(以下代码仅作参考)——
123             if (trade_status.equals("WAIT_BUYER_PAY")) {
124                 // 该判断表示买家已在支付宝交易管理中产生了交易记录,但没有付款
125 
126                 // 判断该笔订单是否在商户网站中已经做过处理(可参考“集成教程”中“3.4返回数据处理”)
127                 // 如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
128                 // 如果有做过处理,不执行商户的业务程序
129                 // 不做处理
130                 out.println("success"); // 请不要修改或删除
131             } else if (trade_status.equals("WAIT_SELLER_SEND_GOODS")) {
132                 // 该判断表示买家已在支付宝交易管理中产生了交易记录且付款成功,但卖家没有发货
133 
134                 // 判断该笔订单是否在商户网站中已经做过处理(可参考“集成教程”中“3.4返回数据处理”)
135                 // 如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
136                 // 如果有做过处理,不执行商户的业务程序
137 
138                     
139                 out.println("success"); // 请不要修改或删除
140             } else if (trade_status.equals("WAIT_BUYER_CONFIRM_GOODS")) {
141                 // 该判断表示卖家已经发了货,但买家还没有做确认收货的操作
142 
143                 // 判断该笔订单是否在商户网站中已经做过处理(可参考“集成教程”中“3.4返回数据处理”)
144                 // 如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
145                 // 如果有做过处理,不执行商户的业务程序
146 
147                 out.println("success"); // 请不要修改或删除
148             } else if (trade_status.equals("TRADE_FINISHED")) {
149                 // 该判断表示买家已经确认收货,这笔交易完成
150 
151                 // 判断该笔订单是否在商户网站中已经做过处理(可参考“集成教程”中“3.4返回数据处理”)
152                 // 如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
153                 // 如果有做过处理,不执行商户的业务程序
154 
155 
156                 out.println("success"); // 请不要修改或删除
157             } else {
158                 out.println("success"); // 请不要修改或删除
159             }
160             // ——请根据您的业务逻辑来编写程序(以上代码仅作参考)——
161 
162             // 
163         }else {// 验证失败
164             out.println("fail");
165         }
166     }


 

5.3 struts.xml


1     <!-- 上面略,该action不能执行任何跳转 -->
2     <action name="notifyURL" class="AlipayAction" method="notifyURL" />