支付宝api https://docs.open.alipay.com/204/105465/
为了保证交易安全,支付宝采用了一系列的安全手段:
采用HTTPS协议传输交易数据,防止数据被截获,解密。
采用RSA非对称密钥,明确交易双方的身份,保证交易主体的正确性和唯一性
支付宝参数bean如下
private String service;// 接口名称
private String partner;// 合作者身份ID String(16)
private String _input_charset;// 参数编码字符集 String 商户网站使用的编码格式,固定为UTF-8。
private String sign_type;// 签名方式 String 签名类型,目前仅支持RSA。 不可空 RSA
private String sign;// 签名 String 请参见签名
private String notify_url;// 服务器异步通知页面路径
private String app_id;// 客户端号 String 标识客户端。 可空 external
private String appenv;// 客户端来源 String
private String out_trade_no;// 商户网站唯一订单号
private String subject;// 商品名称 String(128)
private String payment_type;// 支付类型 String(4)
private String seller_id;// 卖家支付宝账号
private String total_fee;// 总金额 Number
private String body;// 商品详情 String(512)
private String goods_type;// 商品类型 String(1) 具体区分本地交易的商品类型。
private String hb_fq_param;// 花呗分期参数 String Json格式。
private String hb_fq_num;// :花呗分期数,比如分3期支付;
private String rn_check;// 是否发起实名校验 String(1) T:发起实名校验;
private String it_b_pay;// 未付款交易的超时时间 String
private String extern_token;// 授权令牌 String(32)
private String promo_params;// 商户优惠活动参数 String(128)
private String show_url;//商品展示地址,这个链接的作用是在支付宝收银台的商品链接旁边有个下划线“详情”的链接,而点链接弹出的一个新页面便是这个商品展示地址的页面。
封装支付宝请求参数:
AlipayParam param = new AlipayParam();
param.set_input_charset(Constant.UTF8);
param.setBody(content);// 描述如58在线支付
param.setNotify_url(notifyurl);// 异步通知地址(外网能够访问得地址)
param.setOut_trade_no(orderId);// 订单号
param.setPartner(PARTNER);// 合作者账号,String PARTNER = "2088921141789253";// 合作伙伴身份(PID)
param.setService(SERVICE);// 接口名称,mobile.securitypay.pay
param.setTotal_fee(price + "");// 总价格
param.setSubject(subject);// 商品描述
param.setPayment_type("1");// 商品购买
param.setSeller_id(SELLERID);// 卖家,SELLERID = "3131158009@qq.com";// 合作者编码
param.setShow_url("m.alipay.com");//商品展示地址,这个链接的作用是在支付宝收银台的商品链接旁边有个下划线“详情”的链接,而点链接弹出的一个新页面便是这个商品展示地址的页面。
param.setIt_b_pay("30m");
param.setSign(URLEncoder.encode(AlipayUtil.getSign(param.toMap(),
APP_PRIVATE_KEY)));// 签名, String APP_PRIVATE_KEY = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMJ91W9hn8XMyqUt"
+ "kWnxFdUoNrLLmYzuTPEunY6lV6Duo+Xz0pQiEEfig1QiFpF43hNqXuSk21y8JICo"
+ "bSJU76y26yAv/+xT8ey5U8X+041mzuTsQdtZgsZDjWmoK8j6qG9R3Eleco31Bt1f"
+ "FwxFBsVzhXjRFQg/Tx/dIt0ogstbAgMBAAECgYBUi7DhdzWmHY0l2rYwsI2GGLIW"
+ "bS01t02ZNmNlY/jAy5xR1PkATgJ3zT67rwnSeRFIrV/M0uFM4biYeR7f4r5AuzxB"
+ "nM1UlPlDf80IniKsB3ehWcoDmsWi/ggQ0jd5XioZcxlOHTPR+bU878G9VJMqdWTM"
+ "E1cE1qNeTCpSmgOAeQJBAOV+KrKCwcv1gXy4HpbJcPbQUAE4R8ctSh2RUnuYLDwB"
+ "wIGSpdnP7Q09nDep2F81XJAYn0eQ99BqFEmSXq4sYv8CQQDY9Lg7jPyldhM4Ewc2"
+ "esHUxlBAveugaabH1GapPFXyqE3F2SRc2ux7NRIhdnwBxxpBqtJLFLDoKrj//fQl"
+ "QgOlAkEAqrLkuXDvC3FqRkWBYzEk2EDsMWwWX719Mm8EhjATPvMiqH5W5KN3NHEO"
+ "QI0SBwde+UOHPilDWv98ZZj82drkKwJBAKzO2AQO+5orn4lVlrQtOUDqqTe4TvtZ"
+ "zA91PkRkm60Jo9EIcW9IrX5BumxO/N1Jor9VeeV12KdEiFDXDeWzXEUCQQCllXmd"
+ "VYWT6CtSVleBC74L3tw/cznE1mAroh4PNlSdyZMDxa6/i4qzPQT8Q8j1RWHpWrQY"
+ "+ktHA2q/r/z/q6wE";
param.setSign_type(ALGORITHM);// 签名方式ALGORITHM=RSA
return AlipayUtil.getStrFromMap(param.toMap());
生成签名 参数格式如下
app_id=2015052600090779&biz_content={"timeout_express":"30m","product_code":"QUICK_MSECURITY_PAY","total_amount":"0.01","subject":"1","body":"我是测试数据","out_trade_no":"IQJZSRC1YMQB5HU"}&charset=utf-8&format=json&method=alipay.trade.app.pay¬ify_url=http://domain.merchant.com/payment_notify&sign_type=RSA2×tamp=2016-08-25 20:26:31&version=1.0&sign=cYmuUnKi5QdBsoZEAbMXVMmRWjsuUj+y48A2DvWAVVBuYkiBj13CFDHu2vZQvmOfkjE0YqCUQE04kqm9Xg3tIX8tPeIGIFtsIyp/M45w1ZsDOiduBbduGfRo1XRsvAyVAv2hCrBLLrDI5Vi7uZZ77Lo5J0PpUUWwyQGt0M4cj8g=
/**
* 生成签名
*
* @param map
* 参数集合
* @param key
* 商户密钥
* @return
*/
public static String getStrFromMap(Map map) {
ArrayList<String> list = new ArrayList<String>();
Set set = map.keySet();
for (Iterator it = set.iterator(); it.hasNext();) {
String keyStr = (String) it.next();
String value = map.get(keyStr) + "";
if (StringUtils.isNotEmpty(value)) {
list.add(keyStr + "=\"" + value + "\"&");
}
}
int size = list.size();
String[] arrayToSort = (String[]) list.toArray(new String[size]);
Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < size; i++) {
sb.append(arrayToSort[i]);
}
String result = sb.toString();
if (result.lastIndexOf("&") == result.length() - 1) {
result = result.substring(0, result.length() - 1);
}
return result;
}
异步通知:对于App支付产生的交易,支付宝会根据原始支付API中传入的异步通知地址notify_url,通过POST请求的形式将支付结果作为参数通知到商户系统。(回调)
@RequestMapping("/alipayBack")
public void alipayBack(AlipayBackParam param, HttpServletRequest request,
HttpServletResponse response) throws Exception {
String orderId = param.getOut_trade_no();// 订单编号
String status = param.getTrade_status();// 订单状态
if (StringUtils.isBlank(orderId)
|| !(StringUtils.equals(status, AlipayBackParam.TRADE_SUCCESS) || StringUtils
.equals(status, AlipayBackParam.TRADE_FINISHED))) {
return;
}
// 如果支付成功,业务逻辑代码
doPayDone(orderId, param.getTrade_no(), Orders.PAYWAY_ALIPAY);
// 设置页面数据(返回成功,否则支付会一直调用,调用8次)
Map<String, Object> jsonMap = new HashMap<String, Object>();
HtmlUtil.writerJson(response, jsonMap);
}