Java支付宝支付集锦

Java版支付宝支付功能整理文档

作者:Lock-玄清

时间:2017-03-15

注:此文档只支持付款,没有退款的功能

一、引用文件

1基础配置类AlipayConfig.java

package com.alipay.config;

 

/* *

 *类名:AlipayConfig

 *功能:基础配置类

 *详细:设置帐户有关信息及返回路径

 *版本:3.4

 *修改日期:2016-03-08

 *说明:

 *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。

 *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。

 */

public class AlipayConfig {

//↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

 

// 合作身份者ID,签约账号,以2088开头由16位纯数字组成的字符串,查看地址:https://b.alipay.com/order/pidAndKey.htm

public static String partner = "";

// 收款支付宝账号,以2088开头由16位纯数字组成的字符串,一般情况下收款账号就是签约账号

public static String seller_id = partner;

 

// MD5密钥,安全检验码,由数字和字母组成的32位字符串,查看地址:https://b.alipay.com/order/pidAndKey.htm

    public static String key = "";

 

    //----------------pc端支付宝返回路径---------------------

    

// 服务器异步通知页面路径  需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问

public static String notify_url = "";

 

// 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问

public static String return_url = "";

// 签名方式

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

//----------------pc端支付宝调用接口---------------------

// 调用的接口名,无需修改

public static String service = "create_direct_pay_by_user";

//----------------手机端支付宝调用接口---------------------

public static String wap_service = "alipay.wap.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 = "";

//↑↑↑↑↑↑↑↑↑↑请在这里配置防钓鱼信息,如果没开通防钓鱼功能,为空即可 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

}

2支付宝MD5签名处理核心文件MD5.java

package com.alipay.sign;

 

import java.io.UnsupportedEncodingException;

import java.security.SignatureException;

import org.apache.commons.codec.digest.DigestUtils;

 

/**

* 功能:支付宝MD5签名处理核心文件,不需要修改

* 版本:3.3

* 修改日期:2012-08-17

* 说明:

* 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。

* 该代码仅供学习和研究支付宝接口使用,只是提供一个

* */

public class MD5 {

 

    /**

     * 签名字符串

     * @param text 需要签名的字符串

     * @param key 密钥

     * @param input_charset 编码格式

     * @return 签名结果

     */

    public static String sign(String text, String key, String input_charset) {

    text = text + key;

        return DigestUtils.md5Hex(getContentBytes(text, input_charset));

    }

    

    /**

     * 签名字符串

     * @param text 需要签名的字符串

     * @param sign 签名结果

     * @param key 密钥

     * @param input_charset 编码格式

     * @return 签名结果

     */

    public static boolean verify(String text, String sign, String key, String input_charset) {

    text = text + key;

    String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));

    if(mysign.equals(sign)) {

    return true;

    }

    else {

    return false;

    }

    }

 

    /**

     * @param content

     * @param charset

     * @return

     * @throws SignatureException

     * @throws UnsupportedEncodingException

     */

    private static byte[] getContentBytes(String content, String charset) {

        if (charset == null || "".equals(charset)) {

            return content.getBytes();

        }

        try {

            return content.getBytes(charset);

        } catch (UnsupportedEncodingException e) {

            throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);

        }

    }

 

}

 

3支付宝接口公用函数类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 "";

    }

    }

}

 

 

4支付宝通知处理类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 + "¬ify_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;

    }

}

 

 

5支付宝各接口请求提交类AlipaySubmit.java

 

 

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();

    }

}

 

6.自定义订单类UtilDate.java

 

package com.alipay.util;

 

import java.util.Date;

import java.util.Random;

import java.text.SimpleDateFormat;

import java.text.DateFormat;

 

/* *

 *类名:UtilDate

 *功能:自定义订单类

 *详细:工具类,可以用作获取系统日期、订单编号等

 *版本:3.3

 *日期:2012-08-17

 *说明:

 *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。

 *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。

 */

public class UtilDate {

    /** 年月日时分秒(无下划线) yyyyMMddHHmmss */

    public static final String dtLong                  = "yyyyMMddHHmmss";

    

    /** 完整时间 yyyy-MM-dd HH:mm:ss */

    public static final String simple                  = "yyyy-MM-dd HH:mm:ss";

    

    /** 年月日(无下划线) yyyyMMdd */

    public static final String dtShort                 = "yyyyMMdd";

    

    /**

     * 返回系统当前时间(精确到毫秒),作为一个唯一的订单编号

     * @return

     *      以yyyyMMddHHmmss为格式的当前系统时间

     */

public  static String getOrderNum(){

Date date=new Date();

DateFormat df=new SimpleDateFormat(dtLong);

return df.format(date);

}

/**

 * 获取系统当前日期(精确到毫秒),格式:yyyy-MM-dd HH:mm:ss

 * @return

 */

public  static String getDateFormatter(){

Date date=new Date();

DateFormat df=new SimpleDateFormat(simple);

return df.format(date);

}

/**

 * 获取系统当期年月日(精确到天),格式:yyyyMMdd

 * @return

 */

public static String getDate(){

Date date=new Date();

DateFormat df=new SimpleDateFormat(dtShort);

return df.format(date);

}

/**

 * 产生随机的三位数

 * @return

 */

public static String getThree(){

Random rad=new Random();

return rad.nextInt(1000)+"";

}

}

 

7.HttpClient方式访问HttpProtocolHandler.java

 

 

package com.alipay.util.httpClient;

 

import org.apache.commons.httpclient.HttpException;

import java.io.IOException;

import java.net.UnknownHostException;

 

import org.apache.commons.httpclient.HttpClient;

import org.apache.commons.httpclient.HttpConnectionManager;

import org.apache.commons.httpclient.HttpMethod;

import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;

import org.apache.commons.httpclient.NameValuePair;

import org.apache.commons.httpclient.methods.GetMethod;

import org.apache.commons.httpclient.methods.PostMethod;

import org.apache.commons.httpclient.util.IdleConnectionTimeoutThread;

import org.apache.commons.httpclient.methods.multipart.FilePart;

import org.apache.commons.httpclient.methods.multipart.FilePartSource;

import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;

import org.apache.commons.httpclient.methods.multipart.Part;

import org.apache.commons.httpclient.methods.multipart.StringPart;

import org.apache.commons.httpclient.params.HttpMethodParams;

import java.io.File;

import java.util.ArrayList;

import java.util.List;

 

/* *

 *类名:HttpProtocolHandler

 *功能:HttpClient方式访问

 *详细:获取远程HTTP数据

 *版本:3.3

 *日期:2012-08-17

 *说明:

 *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。

 *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。

 */

 

public class HttpProtocolHandler {

 

    private static String              DEFAULT_CHARSET                     = "GBK";

 

    /** 连接超时时间,由bean factory设置,缺省为8秒钟 */

    private int                        defaultConnectionTimeout            = 8000;

 

    /** 回应超时时间, 由bean factory设置,缺省为30秒钟 */

    private int                        defaultSoTimeout                    = 30000;

 

    /** 闲置连接超时时间, 由bean factory设置,缺省为60秒钟 */

    private int                        defaultIdleConnTimeout              = 60000;

 

    private int                        defaultMaxConnPerHost               = 30;

 

    private int                        defaultMaxTotalConn                 = 80;

 

    /** 默认等待HttpConnectionManager返回连接超时(只有在达到最大连接数时起作用):1秒*/

    private static final long          defaultHttpConnectionManagerTimeout = 3 * 1000;

 

    /**

     * HTTP连接管理器,该连接管理器必须是线程安全的.

     */

    private HttpConnectionManager      connectionManager;

 

    private static HttpProtocolHandler httpProtocolHandler                 = new HttpProtocolHandler();

 

    /**

     * 工厂方法

     *

     * @return

     */

    public static HttpProtocolHandler getInstance() {

        return httpProtocolHandler;

    }

 

    /**

     * 私有的构造方法

     */

    private HttpProtocolHandler() {

        // 创建一个线程安全的HTTP连接池

        connectionManager = new MultiThreadedHttpConnectionManager();

        connectionManager.getParams().setDefaultMaxConnectionsPerHost(defaultMaxConnPerHost);

        connectionManager.getParams().setMaxTotalConnections(defaultMaxTotalConn);

 

        IdleConnectionTimeoutThread ict = new IdleConnectionTimeoutThread();

        ict.addConnectionManager(connectionManager);

        ict.setConnectionTimeout(defaultIdleConnTimeout);

 

        ict.start();

    }

 

    /**

     * 执行Http请求

     *

     * @param request 请求数据

     * @param strParaFileName 文件类型的参数名

     * @param strFilePath 文件路径

     * @return 

     * @throws HttpException, IOException

     */

    public HttpResponse execute(HttpRequest request, String strParaFileName, String strFilePath) throws HttpException, IOException {

        HttpClient httpclient = new HttpClient(connectionManager);

 

        // 设置连接超时

        int connectionTimeout = defaultConnectionTimeout;

        if (request.getConnectionTimeout() > 0) {

            connectionTimeout = request.getConnectionTimeout();

        }

        httpclient.getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);

 

        // 设置回应超时

        int soTimeout = defaultSoTimeout;

        if (request.getTimeout() > 0) {

            soTimeout = request.getTimeout();

        }

        httpclient.getHttpConnectionManager().getParams().setSoTimeout(soTimeout);

 

        // 设置等待ConnectionManager释放connection的时间

        httpclient.getParams().setConnectionManagerTimeout(defaultHttpConnectionManagerTimeout);

 

        String charset = request.getCharset();

        charset = charset == null ? DEFAULT_CHARSET : charset;

        HttpMethod method = null;

 

        //get模式且不带上传文件

        if (request.getMethod().equals(HttpRequest.METHOD_GET)) {

            method = new GetMethod(request.getUrl());

            method.getParams().setCredentialCharset(charset);

 

            // parseNotifyConfig会保证使用GET方法时,request一定使用QueryString

            method.setQueryString(request.getQueryString());

        } else if(strParaFileName.equals("") && strFilePath.equals("")) {

        //post模式且不带上传文件

            method = new PostMethod(request.getUrl());

            ((PostMethod) method).addParameters(request.getParameters());

            method.addRequestHeader("Content-Type", "application/x-www-form-urlencoded; text/html; charset=" + charset);

        }

        else {

        //post模式且带上传文件

            method = new PostMethod(request.getUrl());

            List<Part> parts = new ArrayList<Part>();

            for (int i = 0; i < request.getParameters().length; i++) {

            parts.add(new StringPart(request.getParameters()[i].getName(), request.getParameters()[i].getValue(), charset));

            }

            //增加文件参数,strParaFileName是参数名,使用本地文件

            parts.add(new FilePart(strParaFileName, new FilePartSource(new File(strFilePath))));

            

            // 设置请求体

            ((PostMethod) method).setRequestEntity(new MultipartRequestEntity(parts.toArray(new Part[0]), new HttpMethodParams()));

        }

 

        // 设置Http Header中的User-Agent属性

        method.addRequestHeader("User-Agent", "Mozilla/4.0");

        HttpResponse response = new HttpResponse();

 

        try {

            httpclient.executeMethod(method);

            if (request.getResultType().equals(HttpResultType.STRING)) {

                response.setStringResult(method.getResponseBodyAsString());

            } else if (request.getResultType().equals(HttpResultType.BYTES)) {

                response.setByteResult(method.getResponseBody());

            }

            response.setResponseHeaders(method.getResponseHeaders());

        } catch (UnknownHostException ex) {

 

            return null;

        } catch (IOException ex) {

 

            return null;

        } catch (Exception ex) {

 

            return null;

        } finally {

            method.releaseConnection();

        }

        return response;

    }

 

    /**

     * 将NameValuePairs数组转变为字符串

     *

     * @param nameValues

     * @return

     */

    protected String toString(NameValuePair[] nameValues) {

        if (nameValues == null || nameValues.length == 0) {

            return "null";

        }

 

        StringBuffer buffer = new StringBuffer();

 

        for (int i = 0; i < nameValues.length; i++) {

            NameValuePair nameValue = nameValues[i];

 

            if (i == 0) {

                buffer.append(nameValue.getName() + "=" + nameValue.getValue());

            } else {

                buffer.append("&" + nameValue.getName() + "=" + nameValue.getValue());

            }

        }

 

        return buffer.toString();

    }

}

 

 

8Http请求对象的封装HttpRequest.java

 

package com.alipay.util.httpClient;

 

import org.apache.commons.httpclient.NameValuePair;

 

/* *

 *类名:HttpRequest

 *功能:Http请求对象的封装

 *详细:封装Http请求

 *版本:3.3

 *日期:2011-08-17

 *说明:

 *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。

 *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。

 */

 

public class HttpRequest {

 

    /** HTTP GET method */

    public static final String METHOD_GET        = "GET";

 

    /** HTTP POST method */

    public static final String METHOD_POST       = "POST";

 

    /**

     * 待请求的url

     */

    private String url = null;

 

    /**

     * 默认的请求方式

     */

    private String method = METHOD_POST;

 

    private int timeout = 0;

 

    private int connectionTimeout = 0;

 

    /**

     * Post方式请求时组装好的参数值对

     */

    private NameValuePair[] parameters = null;

 

    /**

     * Get方式请求时对应的参数

     */

    private String queryString = null;

 

    /**

     * 默认的请求编码方式

     */

    private String charset = "GBK";

 

    /**

     * 请求发起方的ip地址

     */

    private String clientIp;

 

    /**

     * 请求返回的方式

     */

    private HttpResultType resultType = HttpResultType.BYTES;

 

    public HttpRequest(HttpResultType resultType) {

        super();

        this.resultType = resultType;

    }

 

    /**

     * @return Returns the clientIp.

     */

    public String getClientIp() {

        return clientIp;

    }

 

    /**

     * @param clientIp The clientIp to set.

     */

    public void setClientIp(String clientIp) {

        this.clientIp = clientIp;

    }

 

    public NameValuePair[] getParameters() {

        return parameters;

    }

 

    public void setParameters(NameValuePair[] parameters) {

        this.parameters = parameters;

    }

 

    public String getQueryString() {

        return queryString;

    }

 

    public void setQueryString(String queryString) {

        this.queryString = queryString;

    }

 

    public String getUrl() {

        return url;

    }

 

    public void setUrl(String url) {

        this.url = url;

    }

 

    public String getMethod() {

        return method;

    }

 

    public void setMethod(String method) {

        this.method = method;

    }

 

    public int getConnectionTimeout() {

        return connectionTimeout;

    }

 

    public void setConnectionTimeout(int connectionTimeout) {

        this.connectionTimeout = connectionTimeout;

    }

 

    public int getTimeout() {

        return timeout;

    }

 

    public void setTimeout(int timeout) {

        this.timeout = timeout;

    }

 

    /**

     * @return Returns the charset.

     */

    public String getCharset() {

        return charset;

    }

 

    /**

     * @param charset The charset to set.

     */

    public void setCharset(String charset) {

        this.charset = charset;

    }

 

    public HttpResultType getResultType() {

        return resultType;

    }

 

    public void setResultType(HttpResultType resultType) {

        this.resultType = resultType;

    }

 

}

 

 

9、Http返回对象的封装HttpResponse.java

 

package com.alipay.util.httpClient;

 

import com.alipay.config.AlipayConfig;

 

import org.apache.commons.httpclient.Header;

import java.io.UnsupportedEncodingException;

 

/* *

 *类名:HttpResponse

 *功能:Http返回对象的封装

 *详细:封装Http返回信息

 *版本:3.3

 *日期:2011-08-17

 *说明:

 *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。

 *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。

 */

 

public class HttpResponse {

 

    /**

     * 返回中的Header信息

     */

    private Header[] responseHeaders;

 

    /**

     * String类型的result

     */

    private String   stringResult;

 

    /**

     * btye类型的result

     */

    private byte[]   byteResult;

 

    public Header[] getResponseHeaders() {

        return responseHeaders;

    }

 

    public void setResponseHeaders(Header[] responseHeaders) {

        this.responseHeaders = responseHeaders;

    }

 

    public byte[] getByteResult() {

        if (byteResult != null) {

            return byteResult;

        }

        if (stringResult != null) {

            return stringResult.getBytes();

        }

        return null;

    }

 

    public void setByteResult(byte[] byteResult) {

        this.byteResult = byteResult;

    }

 

    public String getStringResult() throws UnsupportedEncodingException {

        if (stringResult != null) {

            return stringResult;

        }

        if (byteResult != null) {

            return new String(byteResult, AlipayConfig.input_charset);

        }

        return null;

    }

 

    public void setStringResult(String stringResult) {

        this.stringResult = stringResult;

    }

 

}

 

 

10表示Http返回的结果字符方式HttpResultType.java

 

/*

 * Alipay.com Inc.

 * Copyright (c) 2004-2005 All Rights Reserved.

 */

package com.alipay.util.httpClient;

 

/* *

 *类名:HttpResultType

 *功能:表示Http返回的结果字符方式

 *详细:表示Http返回的结果字符方式

 *版本:3.3

 *日期:2012-08-17

 *说明:

 *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。

 *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。

 */

public enum HttpResultType {

    /**

     * 字符串方式

     */

    STRING,

 

    /**

     * 字节数组方式

     */

    BYTES

}

 

 

二、Controller处理方法

1、支付宝PC端支付(即时到账)

1、)支付方法

/**

* 支付宝付款  Lock-玄清

* @throws UnsupportedEncodingException

*/

@RequestMapping("{orderid}/web/alipay.html")

public ModelAndView zhifu(HttpSession session, HttpServletRequest request,@PathVariable("orderid") long orderid) throws UnsupportedEncodingException{

//判断用户登录状态

Userinfo user = getUserLogin(request);

if(user != null){

ModelAndView mv = new ModelAndView("web/alipay");

// 订单查询

Orders orders = orderService.findBydetail(orderid);

// 此方法根据自己的实际情况而定↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

 

// 商户订单号,商户网站订单系统中唯一订单号,必填

String out_trade_no = String.valueOf(orders.getOrderid());

// 订单名称,必填

String subject = new String(String.valueOf(orders.getOrderid()));

// 付款金额,必填

String total_fee = new String(String.format("%.2f", orders.getPrice()).getBytes("ISO-8859-1"), "UTF-8");

System.err.println(total_fee);

// 商品描述,可空

String body = new String(orders.getRemark().getBytes("ISO-8859-1"), "UTF-8");

// 把请求参数打包成数组

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

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", out_trade_no);

sParaTemp.put("subject", subject);

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", "确认");

mv.addObject("sHtmlText", sHtmlText);

System.err.println(sHtmlText);

return mv;

}else{

return new ModelAndView("redirect:../../web/login");

}

}

 

2、)支付成功后的同步调用

 

 /**

 * 同步调用    Lock-玄清

 * @param request

 * @param orderId

 * @throws IOException

 */

@SuppressWarnings("rawtypes")

@RequestMapping("web/return_url.html")

public String returnorder(HttpServletRequest request, HttpServletResponse response) throws IOException {

logger.info("into 同步调用");

 

//获取支付宝GET过来反馈信息

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

Map requestParams = request.getParameterMap();

for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {

String name = (String) iter.next();

String[] values = (String[]) requestParams.get(name);

String valueStr = "";

for (int i = 0; i < values.length; i++) {

valueStr = (i == values.length - 1) ? valueStr + values[i]

: valueStr + values[i] + ",";

}

//乱码解决,这段代码在出现乱码时使用。如果mysignsign不相等也可以使用这段代码转化

valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");

params.put(name, valueStr);

}

//商户订单号

String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");

 

//支付宝交易号

@SuppressWarnings("unused")

String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");

 

//交易状态

String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");

 

//计算得出通知验证结果

boolean verify_result = AlipayNotify.verify(params);

//验证

if(verify_result){//验证成功

//业务逻辑,支付成功后的处理

if(trade_status.equals("TRADE_FINISHED") || trade_status.equals("TRADE_SUCCESS")){

//判断该笔订单是否在商户网站中已经做过处理

//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序

//如果有做过处理,不执行商户的业务程序

logger.info("order pay state success!");

//支付成功后的处理

userandorder(out_trade_no,request);

// 根据自己的需要写处理订单方法↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

 

//返回商户页面

return "web/return_url";

// 注意:

// 退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知

}

logger.info("验证成功");

}else{

//该页面可做页面美工编辑

logger.info("验证失败");

return "web/return_url";

}

return null;

}

 

(4)支付成功后的异步调用

/**

 * 异步调用   Lock-玄清  

 *  

 * @param request

 * @param orderId

 * @throws UnsupportedEncodingException

 */

 

@SuppressWarnings("rawtypes")

@RequestMapping("web/notify_url.html")

public void alrestlu(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {

logger.info("into 异步调用");

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

Map requestParams = request.getParameterMap();

for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {

String name = (String) iter.next();

String[] values = (String[]) requestParams.get(name);

String valueStr = "";

for (int i = 0; i < values.length; i++) {

valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";

}

// 乱码解决,这段代码在出现乱码时使用。如果mysignsign不相等也可以使用这段代码转化

// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");

params.put(name, valueStr);

}

 

// 商户订单号

String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");

 

// 支付宝交易号

@SuppressWarnings("unused")

String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");

 

// 交易状态

String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");

 

if (AlipayNotify.verify(params)) {// 验证成功

// 请在这里加上商户的业务逻辑程序代码

logger.info("Md5通过");

 

// 订单查询

Orders orders = orderService.findBydetail(Long.valueOf(out_trade_no).longValue());

// 判断订单状态是否已经做过更改

if (orders.getStatus() != 1) {

if (trade_status.equals("TRADE_FINISHED") || trade_status.equals("TRADE_SUCCESS")) {

logger.info("异步验证成功");

 

//支付成功后的处理

userandorder(out_trade_no,request);

// 根据自己的需要写处理订单方法↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

 

// 注意:

// 退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知

}

}

} else {// 验证失败

logger.info("异步验证失败");

}

}

 

2、支付宝手机网页支付

1、)支付方法

 

    /**

 * 支付宝手机网站支付   Lock-玄清

 * @param request

 * @param orderid

 * @return

 * @throws UnsupportedEncodingException

 */

@RequestMapping("web/{orderid}/alipaywap.html")

public ModelAndView wapalipay(HttpServletRequest request,@PathVariable("orderid") long orderid) throws UnsupportedEncodingException{

logger.info("支付宝手机网站支付   发起支付");

//判断用户登录状态

Userinfo user = getUserLogin(request);

if(user != null){

ModelAndView mv = new ModelAndView("web/alipaywap");

// 订单查询

Orders orders = orderService.findBydetail(orderid);

 //商户订单号,商户网站订单系统中唯一订单号,必填

String out_trade_no = String.valueOf(orders.getOrderid());

        //订单名称,必填

String subject = new String(String.valueOf(orders.getOrderid()));

        //付款金额,必填

String total_fee = new String(String.format("%.2f", orders.getPrice()).getBytes("ISO-8859-1"), "UTF-8");

       /* //收银台页面上,商品展示的超链接,必填

        String show_url = new String(request.getParameter("").getBytes("ISO-8859-1"),"UTF-8");*/

logger.info("支付宝手机网站支付  发送请求参数!");

//

//把请求参数打包成数组

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

//此参数为wap的参数

sParaTemp.put("service", AlipayConfig.wap_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("out_trade_no", out_trade_no);

sParaTemp.put("subject", subject);

sParaTemp.put("total_fee", total_fee);

/*sParaTemp.put("show_url", show_url);*/

sParaTemp.put("app_pay","Y");//启用此参数可唤起钱包APP支付。

sParaTemp.put("body", "支付宝手机网站支付");

//其他业务参数根据在线开发文档,添加参数.文档地址:https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.2Z6TSk&treeId=60&articleId=103693&docType=1

        //如sParaTemp.put("参数名","参数值");

 

//建立请求

String sHtmlText = AlipaySubmit.buildRequest(sParaTemp,"get","确认");

mv.addObject("sHtmlText", sHtmlText);

return mv;

}else{

return new ModelAndView("redirect:../../web/login");

}

}

 

2、)支付成功后的同步调用

同上

 

 (4) 支付成功后的异步调用

同上

 

三、页面代码

说明:pc端的跳转页面和手机网页支付的跳转页面一致,同步和异步调用的页面一致。故:页面我在这里就只放一个的就可以。

 

1、跳转页面 alipay.jspalipaywap.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<!DOCTYPE html>

<html>

<head lang="zh-cmn-Hans">

<meta charset="UTF-8">

<title>支付宝手机网站支付</title>

</head>

<body>

${sHtmlText}

</body>

</html>

 

2、同步调用页面:return_url.jsp

根据自己的需要画一个支付成功的提示页面

 

3、异步调用页面:notify_url.jsp

根据自己的需要画一个支付成功的提示页面(此页面并没有什么吊用)

 

 

 

备注:此文档是我在项目中运用的,仅为个人观点,还有一部分的不完善,请在使用时,根据自己的项目的实际情况运用。如有疑问,请参考支付宝提供的完整示例或是官方文档。

 

注:文档中没有引入任何jar包,在使用过程注意引入各种jar包。

 

作者:Lock-玄清

时间:2017-03-15

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
接口名称:支付宝手机网站支付接口(alipay.wap.create.direct.pay.by.user)     代码版本:3.3 开发语言:ASP 版 权:支付宝()网络技术有限公司   制 作 者:支付宝技术部技术支持组 联系方式:https://support.open.alipay.com/alipay/support/index.htm 免责声明:DEMO仅供参考,实际开发中需要结合具体场景修改使用。 ───────────────────────────────── ─────── 代码文件结构 ─────── alipay.wap.create.direct.pay.by.user-CSHARP-UTF-8 │ ├class┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈类文件夹 │ │ │ ├alipay_core.asp┈┈┈┈┈┈┈┈┈┈┈┈支付宝接口公用函数文件 │ │ │ ├alipay_md5.asp ┈┈┈┈┈┈┈┈┈┈┈┈MD5签名函数文件 │ │ │ ├alipay_notify.asp┈┈┈┈┈┈┈┈┈┈┈支付宝通知处理类文件 │ │ │ ├alipay_submit.asp┈┈┈┈┈┈┈┈┈┈┈支付宝各接口请求提交类文件 │ │ │ └alipay_config.asp┈┈┈┈┈┈┈┈┈┈┈基础配置文件 │ ├log┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈日志文件夹 │ ├alipayapi.asp┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈支付宝接口入口文件 │ ├index.asp┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈支付宝调试入口页面 │ ├notify_url.asp ┈┈┈┈┈┈┈┈┈┈┈┈┈┈服务器异步通知页面文件 │ ├return_url.asp ┈┈┈┈┈┈┈┈┈┈┈┈┈┈页面跳转同步通知文件 │ └readme.txt ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈使用说明文本 ※注意※ 需要配置的文件是: alipay_config.asp alipayapi.asp notify_url.asp return_url.asp ───────── 类文件函数结构 ───────── alipay_core.asp Function CreateLinkstring(sPara) 功能:把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串 输入:Array sPara 需要拼接的数组 输出:String 拼接完成以后的字符串 Function CreateLinkstringUrlEncode(sPara) 功能:把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并且对其做URLENCODE编码 输入:Array sPara 需要拼接的数组 输出:String 拼接完成以后的字符串 Function FilterPara(sPara) 功能:除去数组中的空值和签名参数 输入:Array sPara 签名参数组 输出:Array 去掉空值与签名参数后的新签名参数组 Function SortPara(sPara) 功能:对数组排序 输入:Array sPara 排序前的数组 输出:Array 排序后的数组 Function Md5Sign(prestr, key, input_charset) 功能:MD5签名 输入:String prestr 需要签名的字符串 String key 私钥 String input_charset 编码格式 输出:String 签名结果 Function Md5Verify(prestr, sign, key, input_charset) 功能:MD5签名 输入:String prestr 需要签名的字符串 String sign 签名结果 String key 私钥 String input_charset 编码格式 输出:String 签名结果 Function LogResult(sWord) 功能:写日志,方便测试(看网站需求,也可以改成存入数据库) 输入:String sWord 要写入日志里的文本内容 Function GetDateTimeFormat() 功能:获取当前时间 格式:年[4位]-月[2位]-日[2位] 小时[2位 24小时制]:分[2位]:秒[2位],如:2007-10-01 13:13:1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值