`
zy77612
  • 浏览: 278657 次
  • 性别: 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
分享到:
评论

相关推荐

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

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

    最新觅知扶风视频解析计费系统源码V1.8.2 免授权优化版 附教程.zip

    后台可对接多个专用json 接口解析,可以 m3u8 资源站对接配置当所有的解析失效时将会启用资源站解析(你也可以留空其他解析只填写资源站解析) 有支持替换资源系统,也可对接第三方资源站,对接支付宝当面付,支持...

    周易宝宝在线起名微信支付宝接口手机自适应

    解析两个域名(包括2级域名)到你的主机站点上,比如解析了www.xxx.com和m.xxx.com分别作为pc端和手机端域名 将根目录下的demo.sql数据库导入到您的mysql数据库内,打开/application/common/Conf/config.php文件,按照...

    扶风解析计费系统1.8全网最新版

    后台可对接多个专用 json 接口解析,可以 m3u8 资源站对接配置当所有的解析失效时将会启用资源站解析(你也可以留空其他解析只填写资源站解析) 有支持替换资源系统,也可对接第三方资源站,对接支付宝当面付,支持...

    Android解析相同接口返回不同格式json数据的方法

    背景原因 目前由双牛掌柜为主导框架开发的一系列产品中,网络请求框架请求到的数据是默认解析成Model类的。即项目中不会手动去解析网络请求到的json数据。...当请求接口时支付宝返回的json如下(隐私数据已隐藏): {

    扶风计费解析系统1.8(20220517版)

    后台可对接多个专用 json 接口解析,可以 m3u8 资源站对接配置当所有的解析失效时将会启用资源站解析(你也可以留空其他解析只填写资源站解析) 有支持替换资源系统,也可对接第三方资源站,对接支付宝当面付,支持...

    最新觅知扶风视频解析计费系统源码V1.8.2 免授权优化版 附教程

    后台可对接多个专用json 接口解析,可以 m3u8 资源站对接配置当所有的解析失效时将会启用资源站解析(你也可以留空其他解析只填写资源站解析) 有支持替换资源系统,也可对接第三方资源站,对接支付宝当面付,支持...

    支付宝申请支付方式流程

    申请支付宝接口的简单流程,包括图文解析。不包括后期开发流程

    iOS开发支付宝支付成功返回字符串的处理操作

    很多朋友在做ios开发项目时,遇到支付宝支付成功返回字符串的处理操作不知道该怎么办,今天小编给大家分享实例代码,需要的朋友参考下

    熊猫办公源码一套完整的PPT网站源码 带数据可采集.zip

    8开发,是一款非常高端的PPT模板,图片素材下载站模板非常适合大型图库下载站,配有手机端模板,支持自定义设置会员组,支持支付宝微信扫码开通VIP,支持每日下载次数限定,支持QQ,微信登录接口。支持火车头数据...

    PHP全开源易支付系统源码带多个支付接口可对接个人免签

    源码介绍: ... 搭建必备:服务器/主机 域名 ...5.支付接口:支持支付宝官方pc扫码、手机网站支付、支付宝当面付;支持QQ官方扫码支付、手机支付;支持微信pc扫码、jsapi公众号支付、微信h5;官方码支付等等

    微信小程序开发之获取用户手机号码(php接口解密)

    而小程序开发文档上边提供的获取手机号码的接口(getPhoneNumber())返回的是密文,需要服务器端进行解密,但是官方提供的开发文档一如既往的乱,如果没有对小程序开发文档有一个整体的了解,搞懂解密流程还是有点难...

    基于java swing 开发的线下支付宝扫码实时订单监控客户端源码

    本客户端基于java swing 开发,实现了个人支付宝账户到账准实时监控,主要思路是定时扫描支付宝账户商家账户详细页面,抓取接口响应数据并解析,展示在系统列表页面

    快速对接payjq的个人微信支付接口过程解析

    近期在了解个人支付接口,希望能解决我在微信上支付的问题。找了很多平台对比再三,感觉 payjq 比较专业。同时支持支付宝和微信,由于本人支付宝还没开通(需要有一定流量才给开通),本文重点讲一下微信收银台模式...

    小程序api实现promise封装过程解析

    这篇文章主要介绍了小程序api实现promise封装过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 微信小程序和支付宝小程序的api封装方法是一样的,都是...

    alipay-mobilepay-java-sdk:支付宝钱包支付接口开发Java SDK

    支付宝钱包移动支付Java SDK[2015-11-4]本SDK实现**"功能流程"**图中的第2和第5步,并提供链接页面中**"数据交互"图中的第1和解析第9步。适用于构建图中所示的基于Java的“商户服务端”**。

    vip影视网站全套源码+自动采集+卡密系统+后台管理+第三方支付

    VIP影视网站源码全套 支持三端 带后台管理 可接第三...多方视频资源可选,超清极速解析,三端均无任何广告,完美观看体验!可接广告可接入第三方支付收费(支付宝,微信,QQ钱包),带卡密系统,有邀请奖励,推广无忧……

    WHMCS5.1破解版

    WHMCS是一套国外流行的域名主机管理软件,跟国内众所周知的IDCSystem一样,主要在用户管理、财务管理、域名接口、服务器管理面板接口等方面...这是WHMCS5.1的破解版,带汉化包,支付宝接口,虽然有点贵,但还是值了。

    pb扩充函数

    1.支持RSA加解密及验签 2.支持条码一维和二维条码 3.支持XML构建及解析 4.支持JSON检构及解析 5.支持FTP操作 6.支持SQL解析 7.... 8.... 9....20.支持微信、支付宝接口 21.支持MD5,RSA,BASE64 22.其它扩展

Global site tag (gtag.js) - Google Analytics