`
zy77612
  • 浏览: 284211 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

支付宝登录接口解析

 
阅读更多

昨天看了支付宝的登录接口代码,觉得有些东西还是对以后的开发有帮助的。下面就记录自己的感想。

首先是AlipayCore.java这个类,该类是请求、通知返回两个文件所调用的公用函数核心处理文件,不需要修改。方法主要是对签名和请求参数进行拼接:

 

  1. /**
  2. * 生成签名结果
  3. * @param sArray 要签名的数组
  4. * @return 签名结果字符串
  5. */
  6. public static String buildMysign(Map<String, String> sArray) {
  7. String prestr = createLinkString(sArray); //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
  8. prestr = prestr + AlipayConfig.key; //把拼接后的字符串再与安全校验码直接连接起来
  9. String mysign = AlipayMd5Encrypt.md5(prestr);
  10. return mysign;
  11. }
  12. /**
  13. * 除去数组中的空值和签名参数
  14. * @param sArray 签名参数组
  15. * @return 去掉空值与签名参数后的新签名参数组
  16. */
  17. public static Map<String, String> paraFilter(Map<String, String> sArray) {
  18. Map<String, String> result = new HashMap<String, String>();
  19. if (sArray == null || sArray.size() <= 0) {
  20. return result;
  21. }
  22. for (String key : sArray.keySet()) {
  23. String value = sArray.get(key);
  24. if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
  25. || key.equalsIgnoreCase("sign_type")) {
  26. continue;
  27. }
  28. result.put(key, value);
  29. }
  30. return result;
  31. }
  32. /**
  33. * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
  34. * @param params 需要排序并参与字符拼接的参数组
  35. * @return 拼接后字符串
  36. */
  37. public static String createLinkString(Map<String, String> params) {
  38. List<String> keys = new ArrayList<String>(params.keySet());
  39. Collections.sort(keys);
  40. String prestr = "";
  41. for (int i = 0; i < keys.size(); i++) {
  42. String key = keys.get(i);
  43. String value = params.get(key);
  44. if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
  45. prestr = prestr + key + "=" + value;
  46. } else {
  47. prestr = prestr + key + "=" + value + "&";
  48. }
  49. }
  50. return prestr;
  51. }
/**
     * 生成签名结果
     * @param sArray 要签名的数组
     * @return 签名结果字符串
     */
    public static String buildMysign(Map<String, String> sArray) {
        String prestr = createLinkString(sArray); //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
        prestr = prestr + AlipayConfig.key; //把拼接后的字符串再与安全校验码直接连接起来
        String mysign = AlipayMd5Encrypt.md5(prestr);
        return mysign;
    }

    /** 
     * 除去数组中的空值和签名参数
     * @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;
    }
AlipayConfig.java这个类是一个基础配置类,主要用来设置账户有关信息和返回路径:
  1. //↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
  2. // 合作身份者ID,以2088开头由16位纯数字组成的字符串
  3. public static String partner = "";
  4. // 交易安全检验码,由数字和字母组成的32位字符串
  5. public static String key = "";
  6. // 当前页面跳转后的页面 要用 http://格式的完整路径,不允许加?id=123这类自定义参数
  7. // 域名不能写成http://localhost/alipay.auth.authorize_jsp_utf8/return_url.jsp ,否则会导致return_url执行无效
  8. public static String return_url = "http://127.0.0.1:8080/alipay.auth.authorize_jsp_utf8/return_url.jsp";
  9. //↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
  10. // 调试用,创建TXT日志路径
  11. public static String log_path = "D:\\alipay_log_" + System.currentTimeMillis()+".txt";
  12. // 字符编码格式 目前支持 gbk 或 utf-8
  13. public static String input_charset = "UTF-8";
  14. // 签名方式 不需修改
  15. public static String sign_type = "MD5";
  16. //访问模式,根据自己的服务器是否支持ssl访问,若支持请选择https;若不支持请选择http
  17. public static String transport = "http";
//↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
	// 合作身份者ID,以2088开头由16位纯数字组成的字符串
	public static String partner = "";
	
	// 交易安全检验码,由数字和字母组成的32位字符串
	public static String key = "";
	
	// 当前页面跳转后的页面 要用 http://格式的完整路径,不允许加?id=123这类自定义参数
	// 域名不能写成http://localhost/alipay.auth.authorize_jsp_utf8/return_url.jsp ,否则会导致return_url执行无效
	public static String return_url = "http://127.0.0.1:8080/alipay.auth.authorize_jsp_utf8/return_url.jsp";

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

	// 调试用,创建TXT日志路径
	public static String log_path = "D:\\alipay_log_" + System.currentTimeMillis()+".txt";

	// 字符编码格式 目前支持 gbk 或 utf-8
	public static String input_charset = "UTF-8";
	
	// 签名方式 不需修改
	public static String sign_type = "MD5";
	
	//访问模式,根据自己的服务器是否支持ssl访问,若支持请选择https;若不支持请选择http
	public static String transport = "http";
AlipayMd5Encrypt.java这个类是对签名进行加密的工具类,不需要修改即可用:
  1. /**
  2. * 对字符串进行MD5签名
  3. *
  4. * @param text
  5. * 明文
  6. *
  7. * @return 密文
  8. */
  9. public static String md5(String text) {
  10. return DigestUtils.md5Hex(getContentBytes(text, AlipayConfig.input_charset));
  11. }
  12. /**
  13. * @param content
  14. * @param charset
  15. * @return
  16. * @throws SignatureException
  17. * @throws UnsupportedEncodingException
  18. */
  19. private static byte[] getContentBytes(String content, String charset) {
  20. if (charset == null || "".equals(charset)) {
  21. return content.getBytes();
  22. }
  23. try {
  24. return content.getBytes(charset);
  25. } catch (UnsupportedEncodingException e) {
  26. throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
  27. }
  28. }
/**
     * 对字符串进行MD5签名
     * 
     * @param text
     *            明文
     * 
     * @return 密文
     */
    public static String md5(String text) {

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

    }

    /**
     * @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);
        }
    }
接下来是AlipayNotify.java这个类,这个类主要是处理支付宝各接口通知返回:
  1. /**
  2. * HTTPS形式消息验证地址
  3. */
  4. private static final String HTTPS_VERIFY_URL = "https://www.alipay.com/cooperate/gateway.do?service=notify_verify&";
  5. /**
  6. * HTTP形式消息验证地址
  7. */
  8. private static final String HTTP_VERIFY_URL = "http://notify.alipay.com/trade/notify_query.do?";
  9. /**
  10. * 验证消息是否是支付宝发出的合法消息
  11. * @param params 通知返回来的参数数组
  12. * @return 验证结果
  13. */
  14. public static boolean verify(Map<String, String> params) {
  15. String mysign = getMysign(params);
  16. String responseTxt = "true";
  17. if(params.get("notify_id") != null) {responseTxt = verifyResponse(params.get("notify_id"));}
  18. String sign = "";
  19. if(params.get("sign") != null) {sign = params.get("sign");}
  20. //写日志记录(若要调试,请取消下面两行注释)
  21. //String sWord = "responseTxt=" + responseTxt + "\n notify_url_log:sign=" + sign + "&mysign="
  22. // + mysign + "\n notify回来的参数:" + AlipayCore.createLinkString(params);
  23. //AlipayCore.logResult(sWord);
  24. //验证
  25. //responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
  26. //mysign与sign不等,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
  27. if (mysign.equals(sign) && responseTxt.equals("true")) {
  28. return true;
  29. } else {
  30. return false;
  31. }
  32. }
  33. /**
  34. * 根据反馈回来的信息,生成签名结果
  35. * @param Params 通知返回来的参数数组
  36. * @return 生成的签名结果
  37. */
  38. private static String getMysign(Map<String, String> Params) {
  39. Map<String, String> sParaNew = AlipayCore.paraFilter(Params);//过滤空值、sign与sign_type参数
  40. String mysign = AlipayCore.buildMysign(sParaNew);//获得签名结果
  41. return mysign;
  42. }
  43. /**
  44. * 获取远程服务器ATN结果,验证返回URL
  45. * @param notify_id 通知校验ID
  46. * @return 服务器ATN结果
  47. * 验证结果集:
  48. * invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空
  49. * true 返回正确信息
  50. * false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
  51. */
  52. private static String verifyResponse(String notify_id) {
  53. //获取远程服务器ATN结果,验证是否是支付宝服务器发来的请求
  54. String transport = AlipayConfig.transport;
  55. String partner = AlipayConfig.partner;
  56. String veryfy_url = "";
  57. if (transport.equalsIgnoreCase("https")) {
  58. veryfy_url = HTTPS_VERIFY_URL;
  59. } else {
  60. veryfy_url = HTTP_VERIFY_URL;
  61. }
  62. veryfy_url = veryfy_url + "partner=" + partner + "¬ify_id=" + notify_id;
  63. return checkUrl(veryfy_url);
  64. }
  65. /**
  66. * 获取远程服务器ATN结果
  67. * @param urlvalue 指定URL路径地址
  68. * @return 服务器ATN结果
  69. * 验证结果集:
  70. * invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空
  71. * true 返回正确信息
  72. * false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
  73. */
  74. private static String checkUrl(String urlvalue) {
  75. String inputLine = "";
  76. try {
  77. URL url = new URL(urlvalue);
  78. HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
  79. BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection
  80. .getInputStream()));
  81. inputLine = in.readLine().toString();
  82. } catch (Exception e) {
  83. e.printStackTrace();
  84. inputLine = "";
  85. }
  86. return inputLine;
  87. }
/**
     * HTTPS形式消息验证地址
     */
    private static final String HTTPS_VERIFY_URL = "https://www.alipay.com/cooperate/gateway.do?service=notify_verify&";

    /**
     * HTTP形式消息验证地址
     */
    private static final String HTTP_VERIFY_URL  = "http://notify.alipay.com/trade/notify_query.do?";

    /**
     * 验证消息是否是支付宝发出的合法消息
     * @param params 通知返回来的参数数组
     * @return 验证结果
     */
    public static boolean verify(Map<String, String> params) {
        String mysign = getMysign(params);
        String responseTxt = "true";
        if(params.get("notify_id") != null) {responseTxt = verifyResponse(params.get("notify_id"));}
        String sign = "";
        if(params.get("sign") != null) {sign = params.get("sign");}

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


        //验证
        //responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
        //mysign与sign不等,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
        if (mysign.equals(sign) && responseTxt.equals("true")) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 根据反馈回来的信息,生成签名结果
     * @param Params 通知返回来的参数数组
     * @return 生成的签名结果
     */
    private static String getMysign(Map<String, String> Params) {
        Map<String, String> sParaNew = AlipayCore.paraFilter(Params);//过滤空值、sign与sign_type参数
        String mysign = AlipayCore.buildMysign(sParaNew);//获得签名结果
        return mysign;
    }

    /**
    * 获取远程服务器ATN结果,验证返回URL
    * @param notify_id 通知校验ID
    * @return 服务器ATN结果
    * 验证结果集:
    * invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空 
    * true 返回正确信息
    * false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
    */
    private static String verifyResponse(String notify_id) {
        //获取远程服务器ATN结果,验证是否是支付宝服务器发来的请求
        String transport = AlipayConfig.transport;
        String partner = AlipayConfig.partner;
        String veryfy_url = "";
        if (transport.equalsIgnoreCase("https")) {
            veryfy_url = HTTPS_VERIFY_URL;
        } else {
            veryfy_url = HTTP_VERIFY_URL;
        }
        veryfy_url = veryfy_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;
    }
下面我们就需要进行alipay的访问请求了,在请求过程中我们要有请求参数数组,提交的表单,有了这些条件之后我们就可以进行模拟HTTP请求获得返回的数据了。生成请求参数数组的代码如下:
  1. /**
  2. * 生成要请求给支付宝的参数数组
  3. * @param sParaTemp 请求前的参数数组
  4. * @return 要请求的参数数组
  5. */
  6. private static Map<String, String> buildRequestPara(Map<String, String> sParaTemp) {
  7. //除去数组中的空值和签名参数
  8. Map<String, String> sPara = AlipayCore.paraFilter(sParaTemp);
  9. //生成签名结果
  10. String mysign = AlipayCore.buildMysign(sPara);
  11. //签名结果与签名方式加入请求提交参数组中
  12. sPara.put("sign", mysign);
  13. sPara.put("sign_type", AlipayConfig.sign_type);
  14. return sPara;
  15. }
/**
     * 生成要请求给支付宝的参数数组
     * @param sParaTemp 请求前的参数数组
     * @return 要请求的参数数组
     */
    private static Map<String, String> buildRequestPara(Map<String, String> sParaTemp) {
        //除去数组中的空值和签名参数
        Map<String, String> sPara = AlipayCore.paraFilter(sParaTemp);
        //生成签名结果
        String mysign = AlipayCore.buildMysign(sPara);

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

        return sPara;
    }
构造提交表单代码:
  1. /**
  2. * 构造提交表单HTML数据
  3. * @param sParaTemp 请求参数数组
  4. * @param gateway 网关地址
  5. * @param strMethod 提交方式。两个值可选:post、get
  6. * @param strButtonName 确认按钮显示文字
  7. * @return 提交表单HTML文本
  8. */
  9. public static String buildForm(Map<String, String> sParaTemp, String gateway, String strMethod,
  10. String strButtonName) {
  11. //待请求参数数组
  12. Map<String, String> sPara = buildRequestPara(sParaTemp);
  13. List<String> keys = new ArrayList<String>(sPara.keySet());
  14. StringBuffer sbHtml = new StringBuffer();
  15. sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\" action=\"" + gateway
  16. + "_input_charset=" + AlipayConfig.input_charset + "\" method=\"" + strMethod
  17. + "\">");
  18. for (int i = 0; i < keys.size(); i++) {
  19. String name = (String) keys.get(i);
  20. String value = (String) sPara.get(name);
  21. sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>");
  22. }
  23. //submit按钮控件请不要含有name属性
  24. sbHtml.append("<input type=\"submit\" value=\"" + strButtonName + "\" style=\"display:none;\"></form>");
  25. sbHtml.append("<script>document.forms['alipaysubmit'].submit();</script>");
  26. return sbHtml.toString();
  27. }
/**
     * 构造提交表单HTML数据
     * @param sParaTemp 请求参数数组
     * @param gateway 网关地址
     * @param strMethod 提交方式。两个值可选:post、get
     * @param strButtonName 确认按钮显示文字
     * @return 提交表单HTML文本
     */
    public static String buildForm(Map<String, String> sParaTemp, String gateway, 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=\"" + gateway
                      + "_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();
    }
构造模拟远程HTTP的POST请求,获取支付宝的返回XML处理结果:
  1. public static String sendPostInfo(Map<String, String> sParaTemp, String gateway)
  2. throws Exception {
  3. //待请求参数数组
  4. Map<String, String> sPara = buildRequestPara(sParaTemp);
  5. HttpProtocolHandler httpProtocolHandler = HttpProtocolHandler.getInstance();
  6. HttpRequest request = new HttpRequest(HttpResultType.BYTES);
  7. //设置编码集
  8. request.setCharset(AlipayConfig.input_charset);
  9. request.setParameters(generatNameValuePair(sPara));
  10. request.setUrl(gateway+"_input_charset="+AlipayConfig.input_charset);
  11. HttpResponse response = httpProtocolHandler.execute(request);
  12. if (response == null) {
  13. return null;
  14. }
  15. String strResult = response.getStringResult();
  16. return strResult;
  17. }
public static String sendPostInfo(Map<String, String> sParaTemp, String gateway)
                                                                                    throws Exception {
        //待请求参数数组
        Map<String, String> sPara = buildRequestPara(sParaTemp);

        HttpProtocolHandler httpProtocolHandler = HttpProtocolHandler.getInstance();

        HttpRequest request = new HttpRequest(HttpResultType.BYTES);
        //设置编码集
        request.setCharset(AlipayConfig.input_charset);

        request.setParameters(generatNameValuePair(sPara));
        request.setUrl(gateway+"_input_charset="+AlipayConfig.input_charset);

        HttpResponse response = httpProtocolHandler.execute(request);
        if (response == null) {
            return null;
        }
        
        String strResult = response.getStringResult();

        return strResult;
    }
generatNameValuePair方法:
  1. /**
  2. * MAP类型数组转换成NameValuePair类型
  3. * @param properties MAP类型数组
  4. * @return NameValuePair类型数组
  5. */
  6. private static NameValuePair[] generatNameValuePair(Map<String, String> properties) {
  7. NameValuePair[] nameValuePair = new NameValuePair[properties.size()];
  8. int i = 0;
  9. for (Map.Entry<String, String> entry : properties.entrySet()) {
  10. nameValuePair[i++] = new NameValuePair(entry.getKey(), entry.getValue());
  11. }
  12. return nameValuePair;
  13. }
/**
     * MAP类型数组转换成NameValuePair类型
     * @param properties  MAP类型数组
     * @return NameValuePair类型数组
     */
    private static NameValuePair[] generatNameValuePair(Map<String, String> properties) {
        NameValuePair[] nameValuePair = new NameValuePair[properties.size()];
        int i = 0;
        for (Map.Entry<String, String> entry : properties.entrySet()) {
            nameValuePair[i++] = new NameValuePair(entry.getKey(), entry.getValue());
        }

        return nameValuePair;
    }
接下来要看看HttpProtocolHandler.java这个类了,这个类是模拟HTTP请求的核心类,最主要的是execute这个执行http请求的方法:
  1. public HttpResponse execute(HttpRequest request) {
  2. HttpClient httpclient = new HttpClient(connectionManager);
  3. // 设置连接超时
  4. int connectionTimeout = defaultConnectionTimeout;
  5. if (request.getConnectionTimeout() > 0) {
  6. connectionTimeout = request.getConnectionTimeout();
  7. }
  8. httpclient.getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);
  9. // 设置回应超时
  10. int soTimeout = defaultSoTimeout;
  11. if (request.getTimeout() > 0) {
  12. soTimeout = request.getTimeout();
  13. }
  14. httpclient.getHttpConnectionManager().getParams().setSoTimeout(soTimeout);
  15. // 设置等待ConnectionManager释放connection的时间
  16. httpclient.getParams().setConnectionManagerTimeout(defaultHttpConnectionManagerTimeout);
  17. String charset = request.getCharset();
  18. charset = charset == null ? DEFAULT_CHARSET : charset;
  19. HttpMethod method = null;
  20. if (request.getMethod().equals(HttpRequest.METHOD_GET)) {
  21. method = new GetMethod(request.getUrl());
  22. method.getParams().setCredentialCharset(charset);
  23. // parseNotifyConfig会保证使用GET方法时,request一定使用QueryString
  24. method.setQueryString(request.getQueryString());
  25. } else {
  26. method = new PostMethod(request.getUrl());
  27. ((PostMethod) method).addParameters(request.getParameters());
  28. method.addRequestHeader("Content-Type",
  29. "application/x-www-form-urlencoded; text/html; charset=" + charset);
  30. }
  31. // 设置Http Header中的User-Agent属性
  32. method.addRequestHeader("User-Agent", "Mozilla/4.0");
  33. HttpResponse response = new HttpResponse();
  34. try {
  35. httpclient.executeMethod(method);
  36. if (request.getResultType().equals(HttpResultType.STRING)) {
  37. response.setStringResult(method.getResponseBodyAsString());
  38. } else if (request.getResultType().equals(HttpResultType.BYTES)) {
  39. response.setByteResult(method.getResponseBody());
  40. }
  41. response.setResponseHeaders(method.getResponseHeaders());
  42. } catch (UnknownHostException ex) {
  43. return null;
  44. } catch (IOException ex) {
  45. return null;
  46. } catch (Exception ex) {
  47. return null;
  48. } finally {
  49. method.releaseConnection();
  50. }
  51. return response;
  52. }
public HttpResponse execute(HttpRequest request) {
        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;

        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 {
            method = new PostMethod(request.getUrl());
            ((PostMethod) method).addParameters(request.getParameters());
            method.addRequestHeader("Content-Type",
                "application/x-www-form-urlencoded; text/html; charset=" + charset);

        }

        // 设置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;
    }
当然我们需要在new HttpProtocolHandler这个类的时候创建一个线程安全的HTTP连接池,为什么要线程安全,下文会有提示。我们把这个步骤放到私有的构造方法当中:
  1. private HttpProtocolHandler() {
  2. connectionManager = new MultiThreadedHttpConnectionManager();
  3. connectionManager.getParams().setDefaultMaxConnectionsPerHost(defaultMaxConnPerHost);
  4. connectionManager.getParams().setMaxTotalConnections(defaultMaxTotalConn);
  5. IdleConnectionTimeoutThread ict = new IdleConnectionTimeoutThread();
  6. ict.addConnectionManager(connectionManager);
  7. ict.setConnectionTimeout(defaultIdleConnTimeout);
  8. ict.start();
  9. }
private HttpProtocolHandler() {
        connectionManager = new MultiThreadedHttpConnectionManager();
        connectionManager.getParams().setDefaultMaxConnectionsPerHost(defaultMaxConnPerHost);
        connectionManager.getParams().setMaxTotalConnections(defaultMaxTotalConn);

        IdleConnectionTimeoutThread ict = new IdleConnectionTimeoutThread();
        ict.addConnectionManager(connectionManager);
        ict.setConnectionTimeout(defaultIdleConnTimeout);

        ict.start();
    }
然后使用如下方法来使其他类能使用getInstance()方法就获得HttpProtocolHandler这个类的实例对象,并且是线程安全的:
  1. private static HttpProtocolHandler httpProtocolHandler = new HttpProtocolHandler();
  2. /**
  3. * 工厂方法
  4. *
  5. * @return
  6. */
  7. public static HttpProtocolHandler getInstance() {
  8. return httpProtocolHandler;
  9. }
private static HttpProtocolHandler httpProtocolHandler                 = new HttpProtocolHandler();

    /**
     * 工厂方法
     * 
     * @return
     */
    public static HttpProtocolHandler getInstance() {
        return httpProtocolHandler;
    }
此类当中还有一些属性,用来设置http连接的超时时间,连接数等参数:
  1. private static String DEFAULT_CHARSET = "GBK";
  2. /** 连接超时时间,由bean factory设置,缺省为8秒钟 */
  3. private int defaultConnectionTimeout = 8000;
  4. /** 回应超时时间, 由bean factory设置,缺省为30秒钟 */
  5. private int defaultSoTimeout = 30000;
  6. /** 闲置连接超时时间, 由bean factory设置,缺省为60秒钟 */
  7. private int defaultIdleConnTimeout = 60000;
  8. private int defaultMaxConnPerHost = 30;
  9. private int defaultMaxTotalConn = 80;
  10. /** 默认等待HttpConnectionManager返回连接超时(只有在达到最大连接数时起作用):1秒*/
  11. private static final long defaultHttpConnectionManagerTimeout = 3 * 1000;
  12. /**
  13. * HTTP连接管理器,该连接管理器必须是线程安全的.(如何设置线程安全上文已经写了)
  14. */
  15. private HttpConnectionManager connectionManager;
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;
此类当中还有HttpClient和HttpResponse这两个类,这两个类主要是对HTTP请求的封装和返回http的相应消息。这两个类就不在这里讲了,就是两个pojo类,HttpClient里面封装了请求需要的属性比如字符集,请求method,超时时间等,HttpResponse里面是响应头和返回结构的封装。
最后一个是支付宝各接口构造类AlipayService.java,
  1. /**
  2. * 支付宝提供给商户的服务接入网关URL(新)
  3. */
  4. private static final String ALIPAY_GATEWAY_NEW = "https://mapi.alipay.com/gateway.do?";
  5. /**
  6. * 构造快捷登录接口
  7. * @param sParaTemp 请求参数集合
  8. * @return 表单提交HTML信息
  9. */
  10. public static String alipay_auth_authorize(Map<String, String> sParaTemp) {
  11. //增加基本配置
  12. sParaTemp.put("service", "alipay.auth.authorize");
  13. sParaTemp.put("target_service", "user.auth.quick.login");
  14. sParaTemp.put("partner", AlipayConfig.partner);
  15. sParaTemp.put("return_url", AlipayConfig.return_url);
  16. sParaTemp.put("_input_charset", AlipayConfig.input_charset);
  17. String strButtonName = "确认";
  18. return AlipaySubmit.buildForm(sParaTemp, ALIPAY_GATEWAY_NEW, "get", strButtonName);
  19. }
  20. /**
  21. * 用于防钓鱼,调用接口query_timestamp来获取时间戳的处理函数
  22. * 注意:远程解析XML出错,与服务器是否支持SSL等配置有关
  23. * @return 时间戳字符串
  24. * @throws IOException
  25. * @throws DocumentException
  26. * @throws MalformedURLException
  27. */
  28. public static String query_timestamp() throws MalformedURLException,
  29. DocumentException, IOException {
  30. //构造访问query_timestamp接口的URL串
  31. String strUrl = ALIPAY_GATEWAY_NEW + "service=query_timestamp&partner=" + AlipayConfig.partner;
  32. StringBuffer result = new StringBuffer();
  33. SAXReader reader = new SAXReader();
  34. Document doc = reader.read(new URL(strUrl).openStream());
  35. List<Node> nodeList = doc.selectNodes("//alipay/*");
  36. for (Node node : nodeList) {
  37. // 截取部分不需要解析的信息
  38. if (node.getName().equals("is_success") && node.getText().equals("T")) {
  39. // 判断是否有成功标示
  40. List<Node> nodeList1 = doc.selectNodes("//response/timestamp/*");
  41. for (Node node1 : nodeList1) {
  42. result.append(node1.getText());
  43. }
  44. }
  45. }
  46. return result.toString();
  47. }
/**
     * 支付宝提供给商户的服务接入网关URL(新)
     */
    private static final String ALIPAY_GATEWAY_NEW = "https://mapi.alipay.com/gateway.do?";

    /**
     * 构造快捷登录接口
     * @param sParaTemp 请求参数集合
     * @return 表单提交HTML信息
     */
    public static String alipay_auth_authorize(Map<String, String> sParaTemp) {

    	//增加基本配置
        sParaTemp.put("service", "alipay.auth.authorize");
        sParaTemp.put("target_service", "user.auth.quick.login");
        sParaTemp.put("partner", AlipayConfig.partner);
        sParaTemp.put("return_url", AlipayConfig.return_url);
        sParaTemp.put("_input_charset", AlipayConfig.input_charset);

        String strButtonName = "确认";

        return AlipaySubmit.buildForm(sParaTemp, ALIPAY_GATEWAY_NEW, "get", strButtonName);
    }

    /**
     * 用于防钓鱼,调用接口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;
        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();
    }
到这里支付宝的登录接口基本上已经结束了,讲的不是很详细,具体流程和代码在这里下载:http://download.csdn.net/detail/uohzoaix/4009777
分享到:
评论

相关推荐

    支付宝老版本接口1.0版本

    对于ASP、Java和PHP这三种不同的编程语言,支付宝接口老版本的实现方式各有不同: 1. **ASP**:在ASP中,开发者通常会使用XMLHttpRequest对象或者ActiveXObject("Microsoft.XMLHTTP")来发起HTTP请求,构建并发送...

    asp支付宝支付接口(绝对可用!!)

    7. **错误处理和重试机制**:在调用支付宝接口时,可能会遇到网络问题、服务器错误等,需要有适当的错误处理机制和重试逻辑,保证支付流程的健壮性。 总的来说,使用这个定制的ASP支付宝支付接口,开发者可以在其...

    支付宝接口开发案例

    支付宝接口开发是现代电商、移动应用以及各类在线服务不可或缺的一部分,它使得商家能够接收和处理用户的支付请求,实现便捷的在线交易。在这个案例中,我们将深入探讨支付宝开发接口API的使用,结合实际操作示例和...

    支付宝单笔交易查询接口

    支付宝单笔交易查询接口是支付宝开放平台提供的一项关键服务,旨在帮助商户或开发者获取特定交易的详细信息。这个接口在日常运营中具有重要的作用,例如处理退款、对账、订单状态跟踪等场景。下面我们将详细探讨这个...

    支付宝的接口文档

    支付宝接口文档是开发者进行支付宝集成的关键参考资料,它详细阐述了如何与支付宝系统进行通信,实现各种支付、退款、查询等功能。这份20150616版本的"支付宝钱包支付接口开发包2.0标准版"包含了支付宝的核心接口...

    支付宝支付接口文档及源码

    签名过程是支付宝接口安全的核心,它采用非对称加密算法,如RSA,结合商户私钥和支付宝公钥,确保数据在传输过程中不被篡改。完成签名后,通过HTTP请求发送到支付宝服务器,服务器验证签名无误后,会展示支付页面给...

    支付宝沙箱接口调用

    支付宝沙箱环境是开发者在正式使用支付宝接口前进行测试的重要工具。它提供了一种安全的模拟交易环境,允许开发者在不涉及真实资金的情况下测试和调试应用程序。在这个环境中,你可以尝试各种交易场景,验证你的代码...

    asp版支付宝接口程序

    1. **支付宝接口**:支付宝接口是支付宝提供给商家用于集成其支付系统的一种服务,通过API调用实现交易处理、订单查询、退款等操作。常见的接口包括即时到账、担保交易、手机支付等,商家可以通过这些接口与支付宝...

    支付宝会员免注册登录接口文档

    综上所述,支付宝会员免注册登录接口不仅提供了便捷的登录体验,还通过一系列的安全措施保障了交易的安全性。商户在集成此接口时,应严格按照官方文档执行,确保数据传输的完整性和安全性,从而提升用户体验,促进...

    java 支付宝单笔交易查询接口返回xml解析

    5. 接收并解析返回数据:支付宝接口通常会返回一个XML格式的数据,包含交易状态、交易详情等信息。 对于XML解析,Java提供了多种方式,包括SAX、DOM和JAXB。这里我们以DOM解析为例,来解释如何处理返回的XML数据: ...

    asp.net实现的支付宝接口

    在ASP.NET 2.0开发环境中,集成支付宝接口是一项常见的任务,这主要涉及到在线支付功能的实现,使得用户可以通过支付宝这个流行的支付平台进行购物或服务的支付。在本项目中,"asp.net 2.0实现的支付宝接口"是核心...

    这是一个关于支付宝的接口程序

    支付宝接口程序是在线支付系统中不可或缺的一部分,尤其在电商、服务类网站中广泛使用。这个压缩包包含了与支付宝交互所需的一些关键文件,让我们逐一解析它们并深入理解其中的知识点。 首先,`alipay.gif` 可能是...

    php支付宝转账接口封装,简单配置即可可用

    4. **发起请求并处理响应**:通过客户端对象调用转账接口,传递构造好的请求参数,然后接收并解析支付宝返回的响应。响应中通常包含了转账的结果状态,如成功、失败等,以及可能的错误信息。 5. **异常处理**:在...

    支付宝接口,支付宝免签约接口

    在本篇文章中,我们将深入探讨这个话题,并以"支付宝接口,支付宝免签约接口"为主题,结合"支付接口"的标签,详细解析这一技术的应用及其优势。 首先,免签约接口意味着开发者或商家无需通过传统方式与支付宝签订...

    支付宝立即到款接口和退款接口

    本文将深入解析这两个接口的使用,以及如何通过Java进行调用。 首先,我们来理解“立即到款接口”。在电子商务中,`create_direct_pay_by_user`接口通常用于实现用户快速支付功能。它允许商家通过API直接发起一个...

    支付宝java接口

    2. **签名机制**: 支付宝接口使用了非对称加密的RSA算法进行签名,确保数据传输过程中的安全性。商户使用自己的私钥对请求参数进行签名,而支付宝会用商户的公钥来验证签名的有效性。 3. **请求接口**: 使用SDK中的...

    java支付宝即时到帐接口

    Java支付宝即时到帐接口是支付宝为开发者提供的一种在线支付服务,允许商家系统与支付宝服务器进行交互,实现快速、安全的转账功能。这个接口主要用于那些希望在用户购买商品或服务后立即完成交易的商家,比如电商...

    Android支付宝授权,支付宝登录demo

    在Android应用开发中,集成支付宝服务是常见的需求,如实现支付宝授权登录或支付功能。本文将详细介绍如何在Android项目中实现支付宝授权登录的流程,并提供一个简洁高效的示例。 首先,我们需要了解支付宝开放平台...

    支付宝接口大全 ASP版

    支付宝接口大全 ASP版是针对使用ASP(Active Server Pages)编程语言进行在线支付集成的一个资源集合。这个压缩包包含了实现支付宝不同支付方式的示例代码,包括纯担保交易和即时到账交易,同时也允许用户根据自己的...

Global site tag (gtag.js) - Google Analytics