官方文档
支付接口(alipay.trade.page.pay):
- 商户系统请求支付宝接口alipay.trade.page.pay,支付宝对商户请求参数进行校验,而后重定向至用户登录页面。
- 用户确认支付后,支付宝get请求returnUrl(商户入参传入),返回同步返回参数。
交易成功后,支付宝post请求notifyUrl(商户入参传入),返回异步通知参数。 - 若由于网络等问题异步通知没有到达,商户可自行调用alipay.trade.query接口进行查询,根据查询接口获取交易以及支付信息(商户也可以直接调用查询接口,不需要依赖异步通知)。
电脑网站支付和微信支付模式二很有相似点:微信支付-模式二,只是最后一步的处理有点小差别
代码编写(可参考官方demo:支付宝SDK、demo下载)
- 首先下载sdk导入项目(此步骤省略)
- 注入支付宝sdk到Spring
引入阿里配置:pay.properties
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>/WEB-INF/config/application.properties</value>
<value>/WEB-INF/config/qqconnectconfig.properties</value>
<value>/WEB-INF/config/pay.properties</value>
</list>
</property>
</bean>
pay.properties
#支付宝支付参数
#dev环境:ali.serverUrl=https://openapi.alipaydev.com/gateway.do
ali.serverUrl=https://openapi.alipay.com/gateway.do
ali.appId=xxxx
ali.privateKey=xxxx
ali.format=json
ali.charset=utf-8
ali.alipayPulicKey=xxxx
ali.signType=RSA2
#通知地址
ali.notifyUrl=http://xxxx/xxxx/xxxx.do
#回调地址
ali.returnUrl=http://xxxx/xxxx/xxxx.do
Spring注入支付宝sdk
<!--阿里支付api-->
<bean name="defaultAlipayClient" class="com.alipay.api.DefaultAlipayClient">
<constructor-arg name="serverUrl" value="${ali.serverUrl}"/>
<constructor-arg name="appId" value="${ali.appId}"/>
<constructor-arg name="privateKey" value="${ali.privateKey}"/>
<constructor-arg name="format" value="${ali.format}"/>
<constructor-arg name="charset" value="${ali.charset}"/>
<constructor-arg name="alipayPulicKey" value="${ali.alipayPulicKey}"/>
<constructor-arg name="signType" value="${ali.signType}"/>
</bean>
- 支付接口
/**
* 阿里支付
*
* @param money 金额
*/
@RequestMapping(value = "aliPay")
public String aliPay(HttpServletResponse res, HttpServletRequest request,
@RequestParam BigDecimal money) throws IOException {
final String session = BaseUtil.getUserSession(request);
if (StringUtils.isBlank(session)) {
LOG.error(String.format("pc阿里支付错误:%s", "用户未登录"));
return "redirect:/view/404.html";
}
//保存订单
final PayModel aliPayModel;
try {
aliPayModel = webUserPayManager.requestAliPay(money, session);
} catch (AlipayApiException e) {
e.printStackTrace();
LOG.error(String.format("pc阿里支付错误:%s", e.getMessage()), e);
return "redirect:/view/404.html";
}
res.setContentType("text/html;charset=utf-8");
//直接将完整的表单html输出到页面
res.getWriter().write(aliPayModel.getBody());
res.getWriter().flush();
res.getWriter().close();
return null;
}
WebUserPayManager
@Autowired
private AliPay aliPay;
/**
* 保存订单信息
*
* @param
* @return
* @throws PayException 支付异常,返回失败抛出异常 回滚订单数据
*/
@Transactional(rollbackFor = Exception.class)
public PayModel requestAliPay(BigDecimal buyMoney, String userId) throws AlipayApiException {
//写入业务逻辑,返回订单信息
final WzzwwUserPay userPay = saveUserPay(buyMoney, userId, false);
Map<String, String> content = new HashMap<>(3);
//订单号
content.put("out_trade_no", userPay.getOrderId());
//总金额
content.put("total_amount", String.valueOf(userPay.getBuyMoney().doubleValue()));
//商品标题
content.put("subject", "xxx");
content.put("product_code", "FAST_INSTANT_TRADE_PAY");
PayModel aliPayModel = aliPay.pagePay(content);
if (!aliPayModel.isSuccess()) {
throw new PayException(String.format("调用支付出错:%s", aliPayModel.getMsg()));
}
return aliPayModel;
}
AliPay(这里只做了pagePay,注意request,不同的支付使用不一样,可以打开源码包看看,官方文档中也写得很详细),其他参数参考下单接口支付宝统一下单接口
@Value(value = "${ali.alipayPulicKey}")
private String alipayPulicKey;
@Value(value = "${ali.notifyUrl}")
private String notifyUrl;
@Value(value = "${ali.returnUrl}")
private String returnUrl;
@Autowired
private AlipayClient alipayClient;
/**
* 支付
*
* @return
* @throws AlipayApiException
*/
public PayModel pay(Map<String, String> content)
throws AlipayApiException {
return pay(returnUrl, notifyUrl, content);
}
/**
* 支付
*
* @return
* @throws AlipayApiException
*/
public PayModel pay(String returnUrl, String notifyUrl, Map<String, String> content)
throws AlipayApiException {
AlipayTradePrecreateRequest alipayRequest = new AlipayTradePrecreateRequest();
//设置业务参数
alipayRequest.setBizContent(JSONObject.toJSONString(content));
alipayRequest.setNotifyUrl(notifyUrl);
alipayRequest.setReturnUrl(returnUrl);
AlipayTradePrecreateResponse response = alipayClient.execute(alipayRequest);
return new PayModel(response.isSuccess(), response.getMsg(),
JSONObject.parseObject(response.getBody()));
}
/**
* 支付
*
* @return
* @throws AlipayApiException
*/
public PayModel pagePay(Map<String, String> content)
throws AlipayApiException {
return pagePay(returnUrl, notifyUrl, content);
}
/**
* 支付
*
* @return
* @throws AlipayApiException
*/
public PayModel pagePay(String returnUrl, String notifyUrl, Map<String, String> content)
throws AlipayApiException {
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
//设置业务参数
final String bizContent = JSONObject.toJSONString(content);
alipayRequest.setBizContent(bizContent);
alipayRequest.setNotifyUrl(notifyUrl);
alipayRequest.setReturnUrl(returnUrl);
final AlipayTradePagePayResponse response = alipayClient
.pageExecute(alipayRequest);
return new PayModel(response.isSuccess(), response.getMsg(),
response.getBody());
}
public String getAlipayPulicKey() {
return alipayPulicKey;
}
public String getNotifyUrl() {
return notifyUrl;
}
public String getReturnUrl() {
return returnUrl;
}
PayModel
/**
* ali支付返回信息
*
* @author LiRui
* @version 1.0
*/
public class PayModel {
private boolean success;
private String msg;
private JSONObject data;
private String body;
private PayModel() {
}
public PayModel(final boolean success, final JSONObject data) {
this.success = success;
this.data = data;
}
public PayModel(final boolean success, final String msg) {
this.success = success;
this.msg = msg;
}
public PayModel(final boolean success, final String msg, final JSONObject data) {
this.success = success;
this.msg = msg;
this.data = data;
}
public PayModel(final boolean success, final String msg, final String body) {
this.success = success;
this.msg = msg;
this.body = body;
}
public String getMsg() {
return msg;
}
public void setMsg(final String msg) {
this.msg = msg;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(final boolean success) {
this.success = success;
}
public JSONObject getData() {
return data;
}
public void setData(final JSONObject data) {
this.data = data;
}
public String getBody() {
return body;
}
public void setBody(final String body) {
this.body = body;
}
}
这里是调用阿里API生成xml表单,然后返回到页面跳转到阿里支付
- 支付回调接口(配置中的returnUrl地址)
/**
* 阿里回调
*
* @param request
*/
@RequestMapping(value = "aliPayNotify")
public String aliPayNotify(HttpServletRequest request)
throws AlipayApiException, UnsupportedEncodingException {
//获取支付宝GET过来反馈信息
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
String[] values = requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
//乱码解决,这段代码在出现乱码时使用
valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
boolean verifyResult = AlipaySignature
.rsaCheckV1(params, aliPay.getAlipayPulicKey(), "utf-8", "RSA2");
if (!verifyResult) {
LOG.error(String.format("pc阿里支付回调错误,验签失败:%s", params.toString()));
return "redirect:/view/404.html";
}
//验证成功
//业务id
String outTradeNo = params.get("out_trade_no");
final String buyerPayAmount = params.get("total_amount");
if (StringUtil.isEmpty(outTradeNo)) {
LOG.error(String.format("pc阿里支付回调错误,out_trade_no为空:%s", params.toString()));
return "redirect:/view/404.html";
}
//处理订单回调逻辑,设置订单业务
final boolean finishOrder = webUserPayManager
.finishOrder(outTradeNo, BigDecimal.valueOf(Float.valueOf(buyerPayAmount)));
return finishOrder ? "redirect:/view/user/index.jsp#/finance"
: "redirect:/view/index.jsp";
}
官方demo写的也很详细,可以直接参考官方demo。测试使用时一定要是用外网,可以搜索natapp工具使用穿透到外网,官方的沙箱也很好用:支付宝沙箱使用