|
|
|
@@ -0,0 +1,144 @@ |
|
|
|
package com.iformall.douyin.pay; |
|
|
|
|
|
|
|
import java.io.UnsupportedEncodingException; |
|
|
|
import java.net.URLEncoder; |
|
|
|
import java.nio.charset.Charset; |
|
|
|
import java.util.HashMap; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.TreeMap; |
|
|
|
import java.util.Map.Entry; |
|
|
|
|
|
|
|
import org.apache.commons.lang3.StringUtils; |
|
|
|
|
|
|
|
import com.alibaba.fastjson.JSON; |
|
|
|
import com.alibaba.fastjson.JSONObject; |
|
|
|
import com.iformall.douyin.pay.orderQuery.OrderQueryResult; |
|
|
|
import com.iformall.douyin.pay.preOrder.CreatePreOrderResult; |
|
|
|
import com.iformall.douyin.pay.preOrder.DouYinCreatePreOrder; |
|
|
|
import com.iformall.utils.HashUtil; |
|
|
|
import com.iformall.utils.HttpUtil; |
|
|
|
|
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
|
|
|
|
/** |
|
|
|
* 抖音小程序支付 |
|
|
|
* https://microapp.bytedance.com/docs/zh-CN/mini-app/develop/api/open-interface/payment/secure/YE |
|
|
|
* @author alascor |
|
|
|
*/ |
|
|
|
@Slf4j |
|
|
|
public class DouYinPayHelper { |
|
|
|
|
|
|
|
/** |
|
|
|
* urlEncode |
|
|
|
* |
|
|
|
* @param src |
|
|
|
* 微信参数 |
|
|
|
* @return String |
|
|
|
* @throws UnsupportedEncodingException |
|
|
|
* 编码错误 |
|
|
|
*/ |
|
|
|
private static String urlEncode(String src) throws UnsupportedEncodingException { |
|
|
|
return URLEncoder.encode(src, Charset.forName("UTF-8").name()).replace("+", "%20"); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 组装签名的字段 |
|
|
|
* |
|
|
|
* @param params |
|
|
|
* 参数 |
|
|
|
* @param urlEncoder |
|
|
|
* 是否urlEncoder |
|
|
|
* @return String |
|
|
|
*/ |
|
|
|
private static String packageSign(Map<String, String> params, boolean urlEncoder) { |
|
|
|
// 先将参数以其参数名的字典序升序进行排序 |
|
|
|
TreeMap<String, String> sortedParams = new TreeMap<String, String>(params); |
|
|
|
// 遍历排序后的字典,字段内容(不包含 key)与支付 SALT 一起进行字典序排序后,使用&符号链接 |
|
|
|
StringBuilder sb = new StringBuilder(); |
|
|
|
boolean first = true; |
|
|
|
for (Entry<String, String> param : sortedParams.entrySet()) { |
|
|
|
String value = param.getValue(); |
|
|
|
if (StringUtils.isBlank(value)) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (first) { |
|
|
|
first = false; |
|
|
|
} else { |
|
|
|
sb.append("&"); |
|
|
|
} |
|
|
|
if (urlEncoder) { |
|
|
|
try { |
|
|
|
value = urlEncode(value); |
|
|
|
} catch (UnsupportedEncodingException e) { |
|
|
|
} |
|
|
|
} |
|
|
|
sb.append(value); |
|
|
|
} |
|
|
|
return sb.toString(); |
|
|
|
} |
|
|
|
public static String createSign(Map<String, String> params, String sercrect) { |
|
|
|
// 生成签名前先去除sign |
|
|
|
params.remove("sign"); |
|
|
|
params.remove("app_id"); |
|
|
|
params.remove("thirdparty_id"); |
|
|
|
String stringA = packageSign(params, false); |
|
|
|
String stringSignTemp = stringA + "&" + sercrect; |
|
|
|
return HashUtil.md5(stringSignTemp).toUpperCase(); |
|
|
|
} |
|
|
|
|
|
|
|
public static String doPost(String url, Map<String, String> params) { |
|
|
|
return HttpUtil.payPost(url, JSON.toJSONString(params)); |
|
|
|
} |
|
|
|
|
|
|
|
//服务端预下单 |
|
|
|
public static CreatePreOrderResult createPreOrder(DouYinCreatePreOrder preOrder) { |
|
|
|
String response = doPost("https://developer.toutiao.com/api/apps/ecpay/v1/create_order", preOrder.toRequestMap()); |
|
|
|
JSONObject jsonObject = JSON.parseObject(response); |
|
|
|
Integer code = jsonObject.getInteger("err_no"); |
|
|
|
if (null != code && code.intValue() == 0 ) { |
|
|
|
CreatePreOrderResult result = new CreatePreOrderResult(); |
|
|
|
result.setSuccess(true); |
|
|
|
JSONObject data = jsonObject.getJSONObject("data"); |
|
|
|
if (null != data ) { |
|
|
|
result.setOrderId(data.getString("order_id")); |
|
|
|
result.setToken(data.getString("order_token")); |
|
|
|
}else { |
|
|
|
log.error("createPreOrder reponse empity. request: "+JSON.toJSONString(preOrder.toRequestMap())+" response:"+response); |
|
|
|
result.setSuccess(false); |
|
|
|
result.setMsg("createPreOrder reponse empity."+response); |
|
|
|
} |
|
|
|
return result; |
|
|
|
}else { |
|
|
|
log.error("createPreOrder reponse error. request: "+JSON.toJSONString(preOrder.toRequestMap())+" response:"+response); |
|
|
|
CreatePreOrderResult result = new CreatePreOrderResult(); |
|
|
|
result.setSuccess(false); |
|
|
|
result.setMsg("createPreOrder reponse error."+response); |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//订单查询 |
|
|
|
public static OrderQueryResult orderQuery(String appId,String secrect,String orderNo,String thirdParytyId) { |
|
|
|
Map map = new HashMap(); |
|
|
|
map.put("app_id",appId); |
|
|
|
map.put("out_order_no",orderNo); |
|
|
|
map.put("sign",createSign(map, secrect)); |
|
|
|
String response = doPost("https://developer.toutiao.com/api/apps/ecpay/v1/query_order", map); |
|
|
|
JSONObject jsonObject = JSON.parseObject(response); |
|
|
|
JSONObject info = jsonObject.getJSONObject("payment_info"); |
|
|
|
if (null != info) { |
|
|
|
OrderQueryResult result = new OrderQueryResult(); |
|
|
|
result.setChannelGatewayNo(info.getString("channel_gateway_no")); |
|
|
|
result.setChannelNo(info.getString("channel_no")); |
|
|
|
result.setWay(info.getInteger("way")); |
|
|
|
result.setPayTime(info.getString("pay_time")); |
|
|
|
result.setOrderStatus(info.getString("order_status")); |
|
|
|
result.setTotalFee(info.getInteger("total_fee")); |
|
|
|
return result; |
|
|
|
}else { |
|
|
|
log.error("orderQuery reponse error. request: "+JSON.toJSONString(map)+" response:"+response); |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
} |