最近在工作中需要使用支付宝App支付,在初次使用过程中也不可避免的出现了一些问题,那么本次随笔主要是概述支付宝app支付服务端的整个实现过程以及就服务端出现的一些问题做一些总结。
https://open.alipay.com/platform/home.htm
首先需要创建一个应用
然后需要设置应用公钥。
下载支付宝密钥生成器。生成成功之后会有商户应用公钥和私钥,将公钥复制到这里, 私钥请妥善保存。下载地址:https://docs.open.alipay.com/291/106097/。保存设置之后会显示支付宝公钥,请妥善保存。
最后提交审核,等待。
注意:如果应用审核通过上线之后,支付宝公钥忘记后可通过进入应用详情页,按如下图所示查看支付宝公钥。
首先需要下载SDK,https://docs.open.alipay.com/54/104509。
完成之后,需要切换命令行,进入SDK所在目录,执行如下命令。如果命令无法执行,请百度如何配置maven环境变量,配置好之后再执行。
mvn install:install-file -DgroupId=com.alipay.sdk -DartifactId=alipay-sdk-JAVA -Dversion=3.1.0 -Dpackaging=jar -Dfile=SDK文件名.jar
groupId:可以自己定义,pom文件依赖依据与此
artifactId:可以自己定义,pom文件依赖依据与此
version:可以自己定义,pom文件依赖依据与此
packaging:打包方式(jar)
file:文件的路径的路径
在pom.xml中引入依赖,如下。
<!-- 支付宝支付相关start -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.1.0</version>
</dependency>
<!-- 支付宝支付相关end -->
#支付宝支付相关配置
#支付宝分配给开发者的应用Id
aliPayAppId=XXX
#卖家支付宝用户号(对应异步通知返回参数seller_id)(可以不配置,只是异步通知时为了进一步校验而配置)
aliPaySellerId=XXX
#卖家支付宝账号(对应异步通知返回参数seller_email)(可以不配置,只是异步通知时为了进一步校验而配置)
alipayAccount=XXX
#商户应用公钥
rsaPublicKey=XXX
#商户应用私钥(注意,如果是Java语言,需要使用pkcs8格式的私钥,避免出现不可预知的错误)
rsaPrivatKey=XXX
#支付宝公钥
rsaAlipayPublicKey=XXX
#加密方式
signType=XXX
#仅支持JSON
alipayFormat=json
#请求使用的编码格式,如utf-8,gbk,gb2312等
alipayCharset=utf-8
/**
*app支付
*
*@author lp
*@date 2019/1/4 16:32
*/
@ApiOperation("app支付")
@RequestMapping(value = "alipay", method = RequestMethod.POST)
public String alipay(@RequestBody CombinedPaymentDto dto, HttpServletResponse response, HttpServletRequest request) {
response.setHeader("Access-Control-Allow-Origin", "*");
// 获取项目中实际的订单的信息
// 此处是相关业务代码
// 获取配置文件中支付宝相关信息(可以使用自己的方式获取)
String aliPayGateway = PropertiesUtils.getInstace("config/webService.properties").getProperty("aliPayGateway");
String aliPayAppId = PropertiesUtils.getInstace("config/webService.properties").getProperty("aliPayAppId");
String rsaPublicKey = PropertiesUtils.getInstace("config/webService.properties").getProperty("rsaPublicKey");
String rsaPrivatKey = PropertiesUtils.getInstace("config/webService.properties").getProperty("rsaPrivatKey");
String rsaAlipayPublicKey = PropertiesUtils.getInstace("config/webService.properties").getProperty("rsaAlipayPublicKey");
String signType = PropertiesUtils.getInstace("config/webService.properties").getProperty("signType");
String alipayFormat = PropertiesUtils.getInstace("config/webService.properties").getProperty("alipayFormat");
String alipayCharset = PropertiesUtils.getInstace("config/webService.properties").getProperty("alipayCharset");
// 开始使用支付宝SDK中提供的API
AlipayClient alipayClient = new DefaultAlipayClient(aliPayGateway, aliPayAppId, rsaPrivatKey, alipayFormat, alipayCharset, rsaAlipayPublicKey, signType);
// 注意:不同接口这里的请求对象是不同的,这个可以查看蚂蚁金服开放平台的API文档查看
AlipayTradeAppPayRequest alipayRequest = new AlipayTradeAppPayRequest();
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setBody("XXX");
model.setSubject("XXX");
// 唯一订单号 根据项目中实际需要获取相应的
model.setOutTradeNo("");
// 支付超时时间(根据项目需要填写)
model.setTimeoutExpress("30m");
// 支付金额(项目中实际订单的需要支付的金额,金额的获取与操作请放在服务端完成,相对安全)
model.setTotalAmount("");
model.setProductCode("QUICK_MSECURITY_PAY");
alipayRequest.setBizModel(model);
// 支付成功后支付宝异步通知的接收地址url
alipayRequest.setNotifyUrl("XXX/getAlipayNotifyInfo");
// 注意:每个请求的相应对象不同,与请求对象是对应。
AlipayTradeAppPayResponse alipayResponse = null;
try {
alipayResponse = alipayClient.sdkExecute(alipayRequest);
} catch (AlipayApiException e) {
e.printStackTrace();
}
// 返回支付相关信息(此处可以直接将getBody中的内容直接返回,无需再做一些其他操作)
return alipayResponse.getBody();
}
/**
*接收支付宝异步通知消息
*
*@author lp
*@date 2019/1/4 17:19
*/
@ApiOperation("接收支付宝异步通知消息")
@RequestMapping(value = "getAlipayNotifyInfo", method = RequestMethod.POST)
public String getAlipayNotifyInfoOfCombinedPayment(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
response.setHeader("Access-Control-Allow-Origin", "*");
// 解决POST请求中文乱码问题(推荐使用此种方式解决中文乱码,因为是支付宝发送异步通知使用的是POST请求)
request.setCharacterEncoding("UTF-8");
//获取支付宝POST过来反馈信息
Map<String,String> params = new HashMap<>();
Map<String,String[]> requestParams = request.getParameterMap();
for (Iterator<String> 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] + ",";
}
// 官方demo中使用如下方式解决中文乱码,在此本人不推荐使用,可能会出现中文乱码解决无效的问题。
// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
params.put(name, valueStr);
}
// 支付宝公钥(请注意,不是商户公钥)
String rsaAlipayPublicKey = PropertiesUtils.getInstace("config/webService.properties").getProperty("rsaAlipayPublicKey");
String signType = PropertiesUtils.getInstace("config/webService.properties").getProperty("signType");
String alipayCharset = PropertiesUtils.getInstace("config/webService.properties").getProperty("alipayCharset");
boolean signVerified = false;
try {
//调用SDK验证签名
signVerified = AlipaySignature.rsaCheckV1(params, rsaAlipayPublicKey, alipayCharset, signType);
if(signVerified) {
// 验证通知后执行自己项目需要的业务操作
// 一般需要判断支付状态是否为TRADE_SUCCESS
// 更严谨一些还可以判断 1.appid 2.sellerId 3.out_trade_no 4.total_amount 等是否正确,正确之后再进行相关业务操作。
// 成功要返回success,不然支付宝会不断发送通知。
return "success";
}
// 验签失败 笔者在这里是输出log,可以根据需要做一些其他操作
// 失败要返回fail,不然支付宝会不断发送通知。
return "fail";
} catch (AlipayApiException e) {
e.printStackTrace();
// 验签异常 笔者在这里是输出log,可以根据需要做一些其他操作
return "fail";
}
}