支付宝app支付用了3天时间将后台代码给写完了,做得有点粗糙,希望有东西大家可以借鉴
app支付流程,java后台做得其实比较少
直接上代码
String json = "{\"timeout_express\":\"" + timeout_express +
"\",\"product_code\":\"" + product_code +
"\",\"total_amount\":\"" + totalFee +
"\",\"subject\":\"" + subject +
"\",\"body\":\"" + body +
"\",\"out_trade_no\":\"" + paymentID +
"\",\"notify_url\":\"" + notify_url + "\"}";
// logger.info("订单号========================" + paymentID);
//借用支付宝的demo 来构造参数
Map<String, String> params = OrderInfoUtil2_0.buildOrderParamMap(payConfig.getAppId(), true, json);
//构造支付订单参数信息
String orderParam = OrderInfoUtil2_0.buildOrderParam(params);
String privateKey = payConfig.getPrivateKey();
//对支付参数信息进行签名
String sign = OrderInfoUtil.getSign(params, privateKey, true);
String orderInfo = orderParam + "&" + sign;
//防止http请求后将×tamp变成*tim
String replace = orderInfo.replace("×tamp", "wanliu20180506");
OrderInfoUtil2_0这个使用阿里demo就行
WS_APP_PAY_SDK_BASE_2.0\Demo\AndroidDemo_2.0(SDK_15.5.3)\alipay_demo\app\src\main\java\com\alipay\sdk\pay\demo\util
另外这里有坑,就是这个orderInfo里面的×tamp转换,不然后再http请求的时候自动转换成别的
package com.odfly.module.component.Util;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
public class OrderInfoUtil {
/**
* 构造授权参数列表
*
* @param pid
* @param app_id
* @param target_id
* @return
*/
public static Map<String, String> buildAuthInfoMap(String pid, String app_id, String target_id, boolean rsa2) {
Map<String, String> keyValues = new HashMap<String, String>();
// 商户签约拿到的app_id,如:201302220024223
keyValues.put("app_id", app_id);
// 商户签约拿到的pid,如:2088133223816631
keyValues.put("pid", pid);
// 服务接口名称, 固定值
keyValues.put("apiname", "com.alipay.account.auth");
// 商户类型标识, 固定值
keyValues.put("app_name", "mc");
// 业务类型, 固定值
keyValues.put("biz_type", "openservice");
// 产品码, 固定值
keyValues.put("product_id", "APP_FAST_LOGIN");
// 授权范围, 固定值
keyValues.put("scope", "kuaijie");
// 商户唯一标识,如:kkkkk091125
keyValues.put("target_id", target_id);
// 授权类型, 固定值
keyValues.put("auth_type", "AUTHACCOUNT");
// 签名类型
keyValues.put("sign_type", rsa2 ? "RSA2" : "RSA");
return keyValues;
}
/**
* 构造支付订单参数列表
*
* @param app_id
* @return
*/
public static Map<String, String> buildOrderParamMap(String app_id, boolean rsa2,String json) {
Map<String, String> keyValues = new HashMap<String, String>();
keyValues.put("app_id", app_id);
keyValues.put("biz_content", json);
keyValues.put("charset", "utf-8");
keyValues.put("method", "alipay.trade.app.pay");
keyValues.put("sign_type", rsa2 ? "RSA2" : "RSA");
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
java.util.Date date=new java.util.Date();
String str=sdf.format(date);
keyValues.put("timestamp", str);
keyValues.put("version", "1.0");
return keyValues;
}
/**
* 构造支付订单参数信息
*
* @param map 支付订单参数
* @return
*/
public static String buildOrderParam(Map<String, String> map) {
List<String> keys = new ArrayList<String>(map.keySet());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < keys.size() - 1; i++) {
String key = keys.get(i);
String value = map.get(key);
sb.append(buildKeyValue(key, value, true));
sb.append("&");
}
String tailKey = keys.get(keys.size() - 1);
String tailValue = map.get(tailKey);
sb.append(buildKeyValue(tailKey, tailValue, true));
return sb.toString();
}
/**
* 拼接键值对
*
* @param key
* @param value
* @param isEncode
* @return
*/
private static String buildKeyValue(String key, String value, boolean isEncode) {
StringBuilder sb = new StringBuilder();
sb.append(key);
sb.append("=");
if (isEncode) {
try {
sb.append(URLEncoder.encode(value, "UTF-8"));
} catch (UnsupportedEncodingException e) {
sb.append(value);
}
} else {
sb.append(value);
}
return sb.toString();
}
/**
* 对支付参数信息进行签名
*
* @param map 待签名授权信息
* @return
*/
public static String getSign(Map<String, String> map, String rsaKey, boolean rsa2) {
List<String> keys = new ArrayList<String>(map.keySet());
// key排序
Collections.sort(keys);
StringBuilder authInfo = new StringBuilder();
for (int i = 0; i < keys.size() - 1; i++) {
String key = keys.get(i);
String value = map.get(key);
authInfo.append(buildKeyValue(key, value, false));
authInfo.append("&");
}
String tailKey = keys.get(keys.size() - 1);
String tailValue = map.get(tailKey);
authInfo.append(buildKeyValue(tailKey, tailValue, false));
String oriSign = SignUtils.sign(authInfo.toString(), rsaKey, rsa2);
String encodedSign = "";
try {
encodedSign = URLEncoder.encode(oriSign, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return "sign=" + encodedSign;
}
/**
* 要求外部订单号必须唯一。
*
* @return
*/
private static String getOutTradeNo() {
SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss", Locale.getDefault());
Date date = new Date();
String key = format.format(date);
Random r = new Random();
key = key + r.nextInt();
key = key.substring(0, 15);
return key;
}
}
支付宝回调处理
/**
* 支付宝异步通知支付结果
* 预定
*
* @param request
* @return
* @throws Exception
*/
@RequestMapping("/getPayNotify")
@NoAccessRequired
public String getPayNotify(HttpServletRequest request) throws Exception {
logger.error("支付宝回调来了===================" + DateUtil.getDateToStrings(new Date()));
Map<String, String> params = convertRequestParamsToMap(request);
String paramsJson = JSON.toJSONString(params);
logger.error("支付宝回调信息->" + paramsJson);
String appid = params.get("app_id");
AliPayApiConfig aliPayApiConfig = AliPayApiConfigKit.getApiConfig(appid);
//验证签名
boolean signVerified = AlipaySignature.rsaCheckV1(params, aliPayApiConfig.getAlipayPublicKey(),
aliPayApiConfig.getCharset(), aliPayApiConfig.getSignType());
if (signVerified) {
//检查参数
check(params, aliPayApiConfig);
String out_trade_no = params.get("out_trade_no");
String trade_no = params.get("trade_no");
String trade_status = params.get("trade_status");
logger.error("支付宝回调信息,trade_status===================" + trade_status);
if (trade_status.equals("TRADE_FINISHED") || trade_status.equals("TRADE_SUCCESS")) {
logger.error("支付宝回调信息===================支付成功");
userService.payOrderStatusUpate(out_trade_no, trade_no);
return "success";
}
} else {//验证是否来自支付宝的通知失败
logger.error("支付宝回调信息===================支付失败");
return "response fail";
}
return "response fail";
}
在处理异步回调的时候需要进行签名验证,这个 //验证签名
boolean signVerified = AlipaySignature.rsaCheckV1(params, aliPayApiConfig.getAlipayPublicKey(),
aliPayApiConfig.getCharset(), aliPayApiConfig.getSignType());中的aliPayApiConfig.getAlipayPublicKey()使用的是支付宝公钥,支付宝公钥,支付宝公钥,重要的事情说3遍,不要用应用公钥
import com.odfly.module.component.entity.PayConfig;
import com.odfly.module.payManager.ext.kit.StrKit;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Javen
* 2017年5月20日
*/
public class AliPayApiConfigKit {
private static final ThreadLocal<String> TL = new ThreadLocal<String>();
private static final Map<String, AliPayApiConfig> CFG_MAP = new ConcurrentHashMap<String, AliPayApiConfig>();
private static final String DEFAULT_CFG_KEY = "_default_ijpay_key_";
/**
* 添加支付宝支付配置,每个appId只需添加一次,相同appId将被覆盖
*
* @param aliPayApiConfig 支付宝支付配置
* @return {AliPayApiConfig} 支付宝支付配置
*/
public static AliPayApiConfig putApiConfig(AliPayApiConfig aliPayApiConfig) {
if (CFG_MAP.size() == 0) {
CFG_MAP.put(DEFAULT_CFG_KEY, aliPayApiConfig);
}
setThreadLocalAppId(aliPayApiConfig.getAppId());
return CFG_MAP.put(aliPayApiConfig.getAppId(), aliPayApiConfig);
}
public static AliPayApiConfig setThreadLocalAliPayApiConfig(AliPayApiConfig aliPayApiConfig) {
return putApiConfig(aliPayApiConfig);
}
/**
* 扩展支付宝支付配置
*
* @param config PMS配置支付宝支付设置
* @return
*/
public static AliPayApiConfig setThreadLocalWxPayApiConfigEx(PayConfig config) {
AliPayApiConfig apiConfig = AliPayApiConfig.New()
.setAppId(config.getAppId())
.setPrivateKey(config.getPrivateKey())
.setAlipayPublicKey(config.getPublicKey())
.setServiceUrl(config.getServerUrl())
.setCharset("utf-8")
.setSignType("RSA2");
return putApiConfig(apiConfig);
}
public static AliPayApiConfig removeApiConfig(AliPayApiConfig apiConfig) {
return removeApiConfig(apiConfig.getAppId());
}
public static AliPayApiConfig removeApiConfig(String appId) {
return CFG_MAP.remove(appId);
}
public static void setThreadLocalAppId(String appId) {
if (StrKit.isBlank(appId)) {
appId = CFG_MAP.get(DEFAULT_CFG_KEY).getAppId();
}
TL.set(appId);
}
public static void removeThreadLocalAppId() {
TL.remove();
}
public static String getAppId() {
String appId = TL.get();
if (StrKit.isBlank(appId)) {
appId = CFG_MAP.get(DEFAULT_CFG_KEY).getAppId();
}
return appId;
}
public static AliPayApiConfig getAliPayApiConfig() {
String appId = getAppId();
return getApiConfig(appId);
}
public static AliPayApiConfig getApiConfig(String appId) {
AliPayApiConfig cfg = CFG_MAP.get(appId);
if (cfg == null) {
throw new IllegalStateException("需事先调用 AliPayApiConfigKit.putApiConfig(aliPayApiConfig) 将 appId对应的 aliPayApiConfig 对象存入," +
"才可以使用 AliPayApiConfigKit.getAliPayApiConfig() 的系列方法");
}
return cfg;
}
}