百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

java版+支付宝支付和微信支付 java 支付宝

yuyutoo 2024-10-14 16:21 3 浏览 0 评论

最近公司在做支付模块,在接入过程中遇到了很多坑,费了不少事,现在分享一下接入方法,也记录一下,以后可能还用的到。用的是支付宝的即时到帐支付功能和微信的扫码支付功能,相比起来,个人感觉支付宝的文档和接入方式都比微信的容易理解和操作,也不用自己写页面,接入起来比较方便,毕竟是支付起家的,比微信支付少很多坑,下面就分别介绍着两种支付的接入方法。

支付宝支付

1、申请签约

目的是得到开发使用的合作伙伴身份(PID)和MD5秘钥,申请地址(即时到账收款):https://b.alipay.com/order/productDetail.htm?productId=2015110218012942


申请方式在开放平台的文档上有详细说明,这里就不再赘述。

2、接入支付接口

在得到PID和秘钥后就可以接入接口了,首先在开放平台中下载官方的demo(java+MD5版本),支付宝的demo做的非常好,下载下来直接配置下jdk就可以运行了。如果遇到Java compiler level does not match错误,说明你用的eclipse或myeclipse的jdk编译版本与demo的JDK编译版本不一致,修改下jdk编译版本就可以了。其实就用到了4个类,如下图

可以选择把支付功能单独做一个项目,在其他项目调用接口就可以支付,也可以整合到自己的项目里,为了好维护我整合到自己的项目里了。把这四个类放到自己的项目中,引入相应的jar包

2.1、demo中类的说明

AlipayConfig.java类主要是配置参数信息的类

package com.fahai.pay.alipay;

import com.fahai.utils.ProInfoUtil;

/* *

*类名:AlipayConfig

*功能:基础配置类

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

*版本:3.4

*修改日期:2016-03-08

*说明:

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

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

*/

public class AlipayConfig {

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

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

public static String partner = "你自己的PID";

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

public static String seller_id = partner;

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

public static String key = "你自己的MD5秘钥";

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

//异步通知页面,就是接受支付宝支付结果返回信息的Controller,可以处理自己的支付后的逻辑

//测试环境

public static String notify_url = ProInfoUtil.getInstance().getProperty("project_url")+"order/pay/aliPayOrder";

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

//同步跳转的页面,就是支付宝支付成功后页面跳转的url

public static String return_url = ProInfoUtil.getInstance().getProperty("project_url")+"order/pay/payResponse";

// 签名方式

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

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

public static String service = "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 = "";

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

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

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

}

}

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122

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;

}

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124

AlipaySubmit.java模拟form表单请求支付宝支付接口的类

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

}

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135

这几个类调用支付宝接口的是AlipaySubmit,在网页选好购买的商品时,在系统中生成订单,然后进行支付,浏览器跳转到支付宝支付网站,Controller中代码为:

/**

* 支付宝支付页面

*

* @return

* @throws IOException

*/

@RequestMapping(value = "/aliPay")

public void aliPay(HttpServletRequest request, HttpServletResponse response) throws IOException {

LOGGER.info("支付宝支付页面");

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

String orderNo = request.getParameter("orderNo");

//订单名称,必填

String subjectName = request.getParameter("subjectName");

//付款金额,必填

String total_fee = request.getParameter("fee");

//商品描述,可空

String body = "法海风控 " + subjectName;

if ("money".equals(body)) {

body = "法海风控 余额充值";

}

//把请求参数打包成map

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

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

sParaTemp.put("subject", subjectName);

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

response.setHeader("Content-Type", "text/html; charset=UTF-8");

response.setCharacterEncoding("UTF-8");

PrintWriter out = response.getWriter();

System.out.println(sHtmlText);

out.println(sHtmlText);

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

请求aliPay会跳转到支付宝支付页面:


3、接收支付结果通知

在配置好notify_url之后,支付结果会请求相应的接口,我的是order/pay/aliPayOrder,代码如下

/**

* 支付宝支付订单

* @return

* @throws IOException

*/

@ResponseBody

@RequestMapping(value = "pay/aliPayOrder", method = RequestMethod.POST)

public void aliPayOrder(HttpServletRequest request,HttpServletResponse response) throws IOException {

LOGGER.info("支付订单");

//从request中获得参数Map,并返回可读的Map

Map<String, String> params = RequestUtil.getParameterMap(request);

LOGGER.info(params.toString());

//验证支付宝签名

boolean aliSign = AlipayNotify.verify(params);

if (aliSign) {//验证成功

//交易状态

String tradeStatus = params.get("trade_status");

//订单编号

String orderNo = params.get("out_trade_no");

//支付单号

String payNo = params.get("trade_no");

//支付账号

String payAccount = params.get("buyer_email");

//支付金额

String totalFee = params.get("total_fee");

//收款支付宝账号

String sellerId = params.get("seller_id");

if (Constant.ALIPAY_TRADE_SUCCESS.equals(tradeStatus)) {//支付宝支付状态为成功

//验证支付宝返回信息与请求信息一致

if (ProInfoUtil.getInstance().getProperty("alipay_partner").equals(sellerId)) {

//订单处理状态

String orderHandleStatus = "error";

//验证订单未做支付处理

Order order = orderService.queryOrderByOrderNo(orderNo);

//订单已支付

if (Constant.DEALSTATUS_PAY.equals(order.getDealStatus())) {

response.getWriter().print("success");

return;

}

if (null != order && Double.parseDouble(totalFee) == order.getDealPrice() &&

Constant.DEALSTATUS_NOT_PAY.equals(order.getDealStatus())) {//验证金额是否和订单一致

//更新订单为已支付、更新用户套餐余额、添加用户充值记录、添加用户余额支出记录

order.setDealStatus(Constant.DEALSTATUS_PAY);

order.setPayNo(payNo);

order.setPayType(Constant.ALIPAY);

order.setPayAccount(payAccount);

try {

//支付成功处理支付业务

boolean result = orderService.payOrder(order);

if (result) {

//成功后向支付宝返回成功标志

LOGGER.info("支付宝支付成功");

orderHandleStatus = "success";

response.getWriter().print("success");

}

} catch (Exception e) {

e.printStackTrace();

LOGGER.info("支付宝支付失败");

response.getWriter().print("fail");

}

}

//添加支付信息

Map<String, Object> map = new HashMap<String, Object>();

map.put("params", params.toString());

map.put("payType", Constant.ALIPAY);

map.put("orderNo", orderNo);

map.put("handleStatus", orderHandleStatus);

orderService.addPayInfo(map);

}

}

} else {//验证失败

LOGGER.info("支付宝返回验证失败");

response.getWriter().print("fail");

}

}

/**

* 从request中获得参数Map,并返回可读的Map

*

* @param request

* @return

*/

@SuppressWarnings("unchecked")

public static Map getParameterMap(HttpServletRequest request) {

// 参数Map

Map properties = request.getParameterMap();

// 返回值Map

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

Iterator entries = properties.entrySet().iterator();

Map.Entry entry;

String name = "";

String value = "";

while (entries.hasNext()) {

entry = (Map.Entry) entries.next();

name = (String) entry.getKey();

Object valueObj = entry.getValue();

if(null == valueObj){

value = "";

}else if(valueObj instanceof String[]){

String[] values = (String[])valueObj;

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

value = values[i] + ",";

}

value = value.substring(0, value.length()-1);

}else{

value = valueObj.toString();

}

returnMap.put(name, value);

}

return returnMap;

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115

至此,支付宝支付功能已经做完了,其中有几个细节需要添加,比如支付时查询订单状态是否已经支付,是否过期等等,可以根据自己的需求去完善。

支付宝的接入还是很顺利的,如果熟练的话一两天就可以完成了,刚开始写博客,有错误或者不明白的地方欢迎大家指出一起交流学习,共同进步。

由于篇幅问题,我在下一章介绍微信支付的接入。

相关推荐

史上最全的浏览器兼容性问题和解决方案

微信ID:WEB_wysj(点击关注)◎◎◎◎◎◎◎◎◎一┳═┻︻▄(页底留言开放,欢迎来吐槽)●●●...

平面设计基础知识_平面设计基础知识实验收获与总结
平面设计基础知识_平面设计基础知识实验收获与总结

CSS构造颜色,背景与图像1.使用span更好的控制文本中局部区域的文本:文本;2.使用display属性提供区块转变:display:inline(是内联的...

2025-02-21 16:01 yuyutoo

写作排版简单三步就行-工具篇_作文排版模板

和我们工作中日常word排版内部交流不同,这篇教程介绍的写作排版主要是用于“微信公众号、头条号”网络展示。写作展现的是我的思考,排版是让写作在网格上更好地展现。在写作上花费时间是有累积复利优势的,在排...

写一个2048的游戏_2048小游戏功能实现

1.创建HTML文件1.打开一个文本编辑器,例如Notepad++、SublimeText、VisualStudioCode等。2.将以下HTML代码复制并粘贴到文本编辑器中:html...

今天你穿“短袖”了吗?青岛最高23℃!接下来几天气温更刺激……

  最近的天气暖和得让很多小伙伴们喊“热”!!!  昨天的气温到底升得有多高呢?你家有没有榜上有名?...

CSS不规则卡片,纯CSS制作优惠券样式,CSS实现锯齿样式

之前也有写过CSS优惠券样式《CSS3径向渐变实现优惠券波浪造型》,这次再来温习一遍,并且将更为详细的讲解,从布局到具体样式说明,最后定义CSS变量,自定义主题颜色。布局...

柠檬科技肖勃飞:大数据风控助力信用社会建设

...

你的自我界限够强大吗?_你的自我界限够强大吗英文

我的结果:A、该设立新的界限...

行内元素与块级元素,以及区别_行内元素和块级元素有什么区别?

行内元素与块级元素首先,CSS规范规定,每个元素都有display属性,确定该元素的类型,每个元素都有默认的display值,分别为块级(block)、行内(inline)。块级元素:(以下列举比较常...

让“成都速度”跑得潇潇洒洒,地上地下共享轨交繁华
让“成都速度”跑得潇潇洒洒,地上地下共享轨交繁华

去年的两会期间,习近平总书记在参加人大会议四川代表团审议时,对治蜀兴川提出了明确要求,指明了前行方向,并带来了“祝四川人民的生活越来越安逸”的美好祝福。又是一年...

2025-02-21 16:00 yuyutoo

今年国家综合性消防救援队伍计划招录消防员15000名

记者24日从应急管理部获悉,国家综合性消防救援队伍2023年消防员招录工作已正式启动。今年共计划招录消防员15000名,其中高校应届毕业生5000名、退役士兵5000名、社会青年5000名。本次招录的...

一起盘点最新 Chrome v133 的5大主流特性 ?

1.CSS的高级attr()方法CSSattr()函数是CSSLevel5中用于检索DOM元素的属性值并将其用于CSS属性值,类似于var()函数替换自定义属性值的方式。...

竞走团体世锦赛5月太仓举行 世界冠军杨家玉担任形象大使

style="text-align:center;"data-mce-style="text-align:...

学物理能做什么?_学物理能做什么 卢昌海

作者:曹则贤中国科学院物理研究所原标题:《物理学:ASourceofPowerforMan》在2006年中央电视台《对话》栏目的某期节目中,主持人问过我一个的问题:“学物理的人,如果日后不...

你不知道的关于这只眯眼兔的6个小秘密
你不知道的关于这只眯眼兔的6个小秘密

在你们忙着给熊本君做表情包的时候,要知道,最先在网络上引起轰动的可是这只脸上只有两条缝的兔子——兔斯基。今年,它更是迎来了自己的10岁生日。①关于德艺双馨“老艺...

2025-02-21 16:00 yuyutoo

取消回复欢迎 发表评论: