相关官方文档位置:https://docs.open.alipay.com/api_1
阿里的文档还是比较清晰明了的,Java部分的代码更是做了非常棒的封装,引用jar包中的方法,支付宝的流程都类似,可以迅速的写出相应的支付代码;
以alipay.trade.app.pay(统一收单交易支付接口) 为例子:
我们可以看到这些公共请求的参数,其中必填参数是必填的,不能为空,也有相应的格式要求,描述中有很好的解释,非必填参数的话有其实也比较重要
notify_url:支付宝服务器主动通知商户服务器里指定的页面http/https路径。
就是回调的地址:意思是 如果填了回调地址,在支付成功后,阿里方面会主动请求这个地址,将相应的支付信息传给你,这个能使支付更加保险,一般在支付后阿里方面会给app端或web端一个反馈,然后app端可以主动请求查询接口来验证支付是否成功,但之间有个时间差,可能影响用户体验什么的,而填了回调后,能使这个功能更加保险,双重验证总是更加保险,在回调中能做很多事情;
app_auth_token: 其实这个是第三方应用调用支付所必须的字段,类似于微信支付中的access_token,但也有点不同,这个相当于去获取相应的支付授权,但是我遇到第三方应用都把他入驻到阿里的平台中,就不用这个字段了,一定要用第三方应用的话,可以看文档,有请求过程,Java 的代码也封装的很好,获取十分简单。
下面讲主要请求参数我放在代码里面了,我再代码里面通过注释来解释
pom.xml里面要加入相应的jar包
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.3.4.ALL</version>
</dependency>
controller:
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.edgecdj.constant.AliPayProperties;
import com.edgecdj.constant.GlobleConstant;
import com.edgecdj.domain.AliPayModel;
import com.edgecdj.domain.JsonResult;
import com.edgecdj.paydemo.alipay.service.AliPayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
/**
* 支付宝支付
*
* @author cdj
*/
@RestController
@RequestMapping("/AliPay")
@Api("阿里支付")
public class AliPayController {
private Log log = LogFactory.getLog(AliPayController.class);
@Autowired
AliPayService aliPayService;
// @Autowired
// AliPayService aliPayService;
@ApiOperation(value = "测试阿里支付", notes = "测试阿里支付")
@ApiImplicitParams({})
@GetMapping("/TestAlipay")
public JsonResult testAlipay() {
try {
// 这个东西必备
AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do",
AliPayProperties.appid, AliPayProperties.private_key, "json", "UTF-8",
AliPayProperties.alipay_public_key, "RSA2");
// 发起App支付请求
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
// 订单描述
model.setBody("我是测试数据");
// 订单标题
model.setSubject("App支付测试Java");
// 商户订单号 就是商户后台生成的订单号
model.setOutTradeNo("201503200101010011");
// 该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天 (屁股后面的字母一定要带,不然报错)
model.setTimeoutExpress("30m");
// 订单总金额 ,默认单位为元,精确到小数点后两位,取值范围[0.01,100000000]
model.setTotalAmount("0.01");
// 销售产品码 不必填
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
// request.setNotifyUrl("商户外网可以访问的异步地址,不写就是不回调");
// 通过api的方法请求阿里接口获得反馈
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
System.out.println(response.getBody());
if (response.isSuccess()) {
System.out.println("调用成功");
} else {
System.out.println("调用失败");
}
return JsonResult.success(response.getBody());
} catch (Exception e) {
return JsonResult.failMsg(e.getMessage());
}
}
@ApiOperation(value = "Alipay 查询订单状态接口", notes = "Alipay 查询订单状态接口")
@ApiImplicitParams({})
@PostMapping("/AliPayQuery")
public JsonResult aliPayQuery(@RequestBody AliPayModel aliPayModel) {
JSONObject resultObject = aliPayService.alipayQuery(aliPayModel);
Boolean flag = (Boolean) resultObject.get(GlobleConstant.RESULTFLAG);
if (flag) {
return JsonResult.success(resultObject);
} else {
return JsonResult.failMsg(resultObject.get(GlobleConstant.ERRMSG).toString());
}
}
@ApiOperation(value = "Alipay Notify回调", notes = "Alipay Notify回调")
@ApiImplicitParams({})
@PostMapping("/AppAliPayNotify")
public JsonResult appAliPayNotify(HttpServletRequest request) {
try {
aliPayService.appAliPayNotify(request);
return JsonResult.success(null);
} catch (Exception e) {
log.error(e.getMessage(), e);
return JsonResult.failMsg(e.getMessage());
}
}
}
执行成功后会得到这样这样一串数据
{
"result": "success",
"msg": null,
"data": "alipay_sdk=alipay-sdk-java-3.3.4.ALL&app_id=2018071360622098&biz_content=%7B%22body%22%3A%22%E6%88%91%E6%98%AF%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE%22%2C%22out_trade_no%22%3A%22201503200101010011%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%2C%22subject%22%3A%22App%E6%94%AF%E4%BB%98%E6%B5%8B%E8%AF%95Java%22%2C%22timeout_express%22%3A%2230m%22%2C%22total_amount%22%3A%220.01%22%7D&charset=UTF-8&format=json&method=alipay.trade.app.pay&sign=BU%2Bd1TDYXCtWf8r2DJjvULSlgd1Kg%2Fp5jkB09g4NxlERN88xDUdRgtXF1vO8KZXj5dT%2BgTH2Pp%2FZ1lgvilcBAEQaa3W5hr6LzLKMo03VmGGA1UsUVbCNGzwV1ALaT72jcsQhWBC7JfK9b2p%2BNwU34BduQlNw%2Fq6J6wYJgdwoHE%2FokAmNfOnnNADg0sWTYyRZb8IyZP2yHlu4rGz7KTLYiXOyYKQFFnRXgks7hCSmES5omW1lBtxQ%2F63EAR%2Fj1UE%2BYbnyoTKMXiNcsG9%2Fo%2FOgoa2zD9lcxiXYZOrKqGlR8FZXke3FI6I%2FO3lVrTPqq1VgdyDm7kffoM3lwOFB4WUliw%3D%3D&sign_type=RSA2×tamp=2018-07-23+13%3A11%3A12&version=1.0"
}
然后将data里的这串数据传给app端,由App端请求支付接口,就能发起支付了。
其他的支付接口都比较类似,官方文档上也有相应的代码,传入相应的请求参数,举一反三 ,阿里支付的代码还是挺好理解的。
阿里回调回来的参数
controller:
@ApiOperation(value = "Alipay Notify回调", notes = "Alipay Notify回调")
@ApiImplicitParams({})
@PostMapping("/AppAliPayNotify")
public JsonResult appAliPayNotify(HttpServletRequest request) {
try {
aliPayService.appAliPayNotify(request);
return JsonResult.success(null);
} catch (Exception e) {
log.error(e.getMessage(), e);
return JsonResult.failMsg(e.getMessage());
}
}
service:
package com.edgecdj.paydemo.alipay.service.impl;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.alipay.api.internal.util.AlipaySignature;
import com.edgecdj.constant.AliPayProperties;
import com.edgecdj.paydemo.alipay.service.AliPayService;
@Service
@Transactional
public class AlipayServiceImpl implements AliPayService {
private Log log = LogFactory.getLog(AlipayServiceImpl.class);
@Override
public void appAliPayNotify(HttpServletRequest request) {
System.out.println("----------------阿里服务器消费手机回调-------" + request);
Map<String, String> params = new HashMap<String, String>();
Map requestParams = request.getParameterMap();
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
// 乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
params.put(name, valueStr);
}
try {
// 调用SDK验证签名
boolean flag = AlipaySignature.rsaCheckV1(params, AliPayProperties.alipay_public_key,
AliPayProperties.charset, "RSA2");
// 商户订单号
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
// 支付宝交易号
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");
// 交易状态
String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");
String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"), "UTF-8");
String info = "flag==" + flag + ";out_trade_no = " + out_trade_no + ";trade_no" + trade_no
+ ";trade_status = " + trade_status + ";total_amount=" + total_amount;
log.info(info);
if (flag && trade_status.equals("TRADE_SUCCESS")) {
// 修改订单状态
// 已缴费----开始处理业务
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
再强调一下,支付的话验证最好是 查询+notifyurl 接口 ;因为这样跟保险,但需要注意的是自己数据库里面订单状态的修改,毕竟有两次验证,时间上是有差距的,所以在订单状态及费用的处理上需要多加留意。