package com.panzhihua.applets.unionpay;
|
|
import com.panzhihua.common.service.community.CommunityService;
|
import com.panzhihua.common.utlis.DateUtils;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.digest.DigestUtils;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.stereotype.Component;
|
|
import javax.crypto.Mac;
|
import javax.crypto.spec.SecretKeySpec;
|
import java.io.*;
|
import java.net.HttpURLConnection;
|
import java.net.URL;
|
import java.net.URLConnection;
|
import java.time.LocalDateTime;
|
import java.util.List;
|
import java.util.UUID;
|
|
import static com.panzhihua.common.utlis.PayUtil.makeUUID;
|
|
/**
|
* @author kkqiao
|
* 全民付移动支付小程序支付下单接口
|
* 说明:
|
* 本接口为商户的订单信息发向银商网络支付前置系统以获取支付要素商户需遵循商户订单号生成规范,即以银商分配的4位来源编号作为账单号的前4位,且在商户系统中此
|
* 账单号保证唯一。总长度需大于6位,小于28位。银商的推荐规则为(无特殊情况下,建议遵守此规
|
* 则):
|
* {来源编号(4位)}{时间(yyyyMMddmmHHssSSS)(17位)}{7位随机数}
|
* 微信下单成功后,使用返回数据中的miniPayRequest 即可调用支付。
|
* 支付需要集成微信小程序,需要第三方自行配置。
|
* 支付宝下单成功后,使用返回数据中的targetOrderId 即可调用支付。 支付需要集成支付宝支付环境,
|
* 需要第三方自行配置。
|
* 微信:
|
* 测试环境:http://58.247.0.18:29015/v1/netpay/wx/unified-order
|
* 生产环境:https://api-mop.chinaums.com/v1/netpay/wx/unified-order
|
* 支付宝:
|
* 测试环境:http://58.247.0.18:29015/v1/netpay/trade/create
|
* 生产环境:https://api-mop.chinaums.com/v1/netpay/trade/create
|
*/
|
@Slf4j
|
@Component
|
public class UnifiedOrder {
|
// static String url = "https://test-api-open.chinaums.com/v1/netpay/wx/unified-order";
|
static String url = "https://api-mop.chinaums.com/v1/netpay/wx/unified-order";
|
|
public static String sendOrder(String totalAmount,String orderDesc,String productId,String OpenId,LocalDateTime time,String merOrderId)
|
{
|
//1. 组建请求报文
|
UnifiedOrderBody reqBody = new UnifiedOrderBody();
|
reqBody.requestTimestamp = time.format(DateUtils.format_ymdhms);// "2019-08-09 17:30:55";
|
reqBody.merOrderId = merOrderId;
|
reqBody.mid = UnionpayContent.MID;
|
reqBody.tid = UnionpayContent.TID;
|
reqBody.instMid = UnionpayContent.INSTMID;
|
reqBody.totalAmount = totalAmount;
|
reqBody.secureTransaction = "false";
|
reqBody.orderDesc = orderDesc;
|
reqBody.productId = productId;
|
reqBody.notifyUrl = "https://huacheng.psciio.com/api/huacheng-applets/wx/wxNotifyAllUnionpay?merOrderId="+reqBody.merOrderId;
|
reqBody.tradeType = "MINI";
|
reqBody.subOpenId = OpenId;
|
|
log.info("银联支付参数:\n"+reqBody);
|
|
//2. 获取认证报文,timestamp为当前日期,老旧日期无法请求成功
|
String authorization = null;
|
try {
|
authorization = getAuthorization(UnionpayContent.APPID,UnionpayContent.APPKEY,
|
time.format(DateUtils.format_ymdhms_string),"nonce",reqBody.toString());
|
} catch (Exception e) {
|
e.printStackTrace();
|
return "下单失败";
|
}
|
System.out.println("authorization:\n"+authorization);
|
|
//3. 发送http请求,并解析返回信息
|
String response = request(url,authorization,reqBody.toString());
|
System.out.println("response:\n"+response);
|
return response;
|
}
|
|
/**
|
* 发送http请求
|
* @param url 请求url
|
* @param authorization 认证报文
|
* @param reqBody 请求体
|
* @return response
|
*/
|
static String request(String url, String authorization, String reqBody){
|
String response = "";
|
PrintWriter out = null;
|
BufferedReader in = null;
|
try{
|
URL realUrl = new URL(url);
|
URLConnection conn = realUrl.openConnection();
|
HttpURLConnection httpUrlConnection = (HttpURLConnection) conn;
|
httpUrlConnection.setRequestProperty("Content-Type", "application/json");
|
httpUrlConnection.setRequestProperty("authorization",authorization);
|
httpUrlConnection.setDoOutput(true);
|
httpUrlConnection.setDoInput(true);
|
out = new PrintWriter(httpUrlConnection.getOutputStream());
|
out.write(reqBody);
|
out.flush();
|
httpUrlConnection.connect();
|
in = new BufferedReader(new InputStreamReader(httpUrlConnection.getInputStream()));
|
String line;
|
while ((line = in.readLine()) != null) {
|
response += line;
|
}
|
}catch(Exception e){
|
e.printStackTrace();
|
} finally {
|
try {
|
if (out != null) { out.close();}
|
if (in != null) {in.close();}
|
} catch (Exception ex) {
|
ex.printStackTrace();
|
}
|
}
|
return response;
|
}
|
|
/**
|
* 获取签名头
|
* @param appid
|
* @param appkey
|
* @param timestamp 格式:"yyyyMMddHHmmss"
|
* @param nonce 随机字符串,
|
* @param body 请求体
|
* @return authorization 认证报文
|
* @throws Exception
|
*/
|
static String getAuthorization(String appid, String appkey, String timestamp, String nonce, String body) throws Exception {
|
byte[] data = body.getBytes("utf-8");
|
InputStream is = new ByteArrayInputStream(data);
|
String testSH = DigestUtils.sha256Hex(is);
|
String s1 = appid+timestamp+nonce+testSH;
|
Mac mac = Mac.getInstance("HmacSHA256");
|
mac.init(new SecretKeySpec(appkey.getBytes("utf-8"),"HmacSHA256"));
|
byte[] localSignature = mac.doFinal(s1.getBytes("utf-8"));
|
String localSignatureStr = Base64.encodeBase64String(localSignature);
|
return "OPEN-BODY-SIG AppId="+"\""+appid+"\""+", Timestamp="+"\""+timestamp+"\""+", Nonce="+"\""+nonce+"\""+", Signature="+"\""+localSignatureStr+"\"";
|
}
|
|
static class UnifiedOrderBody{
|
//消息ID
|
String msgId;
|
//报文请求时间,格式yyyy-MM-ddHH:mm:ss
|
String requestTimestamp;
|
//商户订单号
|
String merOrderId;
|
//请求系统预留字段
|
String srcReserve;
|
//商户号
|
String mid;
|
//终端号
|
String tid;
|
//业务类型
|
String instMid;
|
//商品信息
|
List<GoodsItem> goods;
|
//商户附加数据
|
String attachedData;
|
//订单过期时间
|
String expireTime;
|
//商品标记
|
String goodsTag;
|
//商品交易单号
|
String goodsTradeNo;
|
//账单描述
|
String orderDesc;
|
//订单原始金额
|
String originalAmount;
|
//商品ID
|
String productId;
|
//支付总金额
|
String totalAmount;
|
//分账标记
|
String divisionFlag;
|
//平台商户分账金额
|
String platformAmount;
|
//子订单信息
|
List<SubOrderItem> subOrders;
|
//支付结果通知地址
|
String notifyUrl;
|
//订单展示页面
|
String showUrl;
|
//担保交易标识
|
String secureTransaction;
|
//用户子标识
|
String tradeType;
|
//交易类型
|
String subOpenId;
|
//商户用户号
|
String merchantUserId;
|
//用户Id
|
String userId;
|
//实名认证手机号
|
String mobile;
|
//是否需要限制信用卡支付
|
String limitCreditCard;
|
|
String toJson(){
|
StringBuilder sb = new StringBuilder();
|
sb.append("{");
|
if (this.userId != null) sb.append("\"userId\":\"" + this.userId + "\",");
|
if (this.msgId != null) sb.append("\"msgId\":\"" + this.msgId + "\",");
|
if (this.requestTimestamp != null) sb.append("\"requestTimestamp\":\"" + this.requestTimestamp + "\",");
|
if (this.merOrderId != null) sb.append("\"merOrderId\":\"" + this.merOrderId + "\",");
|
if (this.srcReserve != null) sb.append("\"srcReserve\":\"" + this.srcReserve + "\",");
|
if (this.mid != null) sb.append("\"mid\":\"" + this.mid + "\",");
|
if (this.tid != null) sb.append("\"tid\":\"" + this.tid + "\",");
|
if (this.instMid != null) sb.append("\"instMid\":\"" + this.instMid + "\",");
|
if (this.goods != null && this.goods.size()>0) {
|
sb.append("\"goods\":[");
|
for(int i=0;i<goods.size();i++){
|
sb.append(goods.get(i));
|
sb.append(",");
|
}
|
if (sb.charAt(sb.length() - 1) == ',')
|
sb.deleteCharAt(sb.length() - 1);
|
sb.append("],");
|
}
|
if (this.attachedData != null) sb.append("\"attachedData\":\"" + this.attachedData + "\",");
|
if (this.expireTime != null) sb.append("\"expireTime\":\"" + this.expireTime + "\",");
|
if (this.goodsTag != null) sb.append("\"goodsTag\":\"" + this.goodsTag + "\",");
|
if (this.goodsTradeNo != null) sb.append("\"goodsTradeNo\":\"" + this.goodsTradeNo + "\",");
|
if (this.orderDesc != null) sb.append("\"orderDesc\":\"" + this.orderDesc + "\",");
|
if (this.originalAmount != null) sb.append("\"originalAmount\":\"" + this.originalAmount + "\",");
|
if (this.productId != null) sb.append("\"productId\":\"" + this.productId + "\",");
|
if (this.totalAmount != null) sb.append("\"totalAmount\":\"" + this.totalAmount + "\",");
|
if (this.divisionFlag != null) sb.append("\"divisionFlag\":\"" + this.divisionFlag + "\",");
|
if (this.platformAmount != null) sb.append("\"platformAmount\":\"" + this.platformAmount + "\",");
|
if (this.subOrders != null && this.subOrders.size()>0) {
|
sb.append("\"subOrders\":[");
|
for(int i=0;i<subOrders.size();i++){
|
sb.append(subOrders.get(i));
|
sb.append(",");
|
}
|
if (sb.charAt(sb.length() - 1) == ',')
|
sb.deleteCharAt(sb.length() - 1);
|
sb.append("],");
|
}
|
if (this.notifyUrl != null) sb.append("\"notifyUrl\":\"" + this.notifyUrl + "\",");
|
if (this.showUrl != null) sb.append("\"showUrl\":\"" + this.showUrl + "\",");
|
if (this.secureTransaction != null) sb.append("\"secureTransaction\":\"" + this.secureTransaction + "\",");
|
if (this.subOpenId != null) sb.append("\"subOpenId\":\"" + this.subOpenId + "\",");
|
if (this.tradeType != null) sb.append("\"tradeType\":\"" + this.tradeType + "\",");
|
if (this.merchantUserId != null) sb.append("\"merchantUserId\":\"" + this.merchantUserId + "\",");
|
if (this.mobile != null) sb.append("\"mobile\":\"" + this.mobile + "\",");
|
if (this.limitCreditCard != null) sb.append("\"limitCreditCard\":\"" + this.limitCreditCard + "\",");
|
if (sb.charAt(sb.length() - 1) == ',')
|
sb.deleteCharAt(sb.length() - 1);
|
sb.append("}");
|
return sb.toString();
|
}
|
|
public String toString(){
|
return this.toJson();
|
}
|
static class GoodsItem {
|
//商品ID
|
String goodsId;
|
//商品名称
|
String goodsName;
|
//商品数量
|
String quantity;
|
//商品单价(分)
|
String price;
|
//商品分类
|
String goodsCategory;
|
//商品说明
|
String body;
|
//商品单位
|
int unit;
|
//商品折扣
|
int discount;
|
//子商户号
|
String subMerchantId;
|
//子商户商品总额
|
int subOrderAmount;
|
|
String toJson(){
|
StringBuilder sb = new StringBuilder();
|
sb.append("{");
|
if(this.goodsId!=null) sb.append("\"goodsId\":\""+this.goodsId+"\",");
|
if(this.goodsName!=null) sb.append("\"goodsName\":\""+this.goodsName+"\",");
|
if(this.quantity!=null) sb.append("\"quantity\":\""+this.quantity+"\",");
|
if(this.price!=null) sb.append("\"price\":\""+this.price+"\",");
|
if(this.goodsCategory!=null) sb.append("\"goodsCategory\":\""+this.goodsCategory+"\",");
|
if(this.body!=null) sb.append("\"body\":\""+this.body+"\",");
|
if(this.unit!=0) sb.append("\"unit\":\""+this.unit+"\",");
|
if(this.discount!=0) sb.append("\"discount\":\""+this.discount+"\",");
|
if(this.subMerchantId!=null) sb.append("\"subMerchantId\":\""+this.subMerchantId+"\",");
|
if(this.subOrderAmount!=0) sb.append("\"subOrderAmount\":\""+this.subOrderAmount+"\",");
|
if(sb.charAt(sb.length()-1) == ',')
|
sb.deleteCharAt(sb.length()-1);
|
sb.append("}");
|
return sb.toString();
|
}
|
public String toString(){
|
return this.toJson();
|
}
|
}
|
static class SubOrderItem{
|
//子商户号
|
String mid;
|
//子商户分账金额
|
int totalAmount;
|
String toJson() {
|
StringBuilder sb = new StringBuilder();
|
sb.append("{");
|
if (this.mid != null) {
|
sb.append("\"mid\":\"" + this.mid + "\",");
|
}
|
if (this.totalAmount != 0) {
|
sb.append("\"totalAmount\":\"" + this.totalAmount + "\",");
|
}
|
if (sb.charAt(sb.length() - 1) == ',')
|
sb.deleteCharAt(sb.length() - 1);
|
sb.append("}");
|
return sb.toString();
|
}
|
|
public String toString(){
|
return this.toJson();
|
}
|
}
|
|
}
|
|
}
|