package com.stylefeng.guns.modular.system.util.LiuZhouBank;
|
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONObject;
|
import com.fop.sdk.*;
|
import com.fop.sdk.domain.*;
|
import com.fop.sdk.request.*;
|
import com.fop.sdk.response.*;
|
import com.stylefeng.guns.core.util.ToolUtil;
|
|
import javax.servlet.http.HttpServletRequest;
|
import java.io.BufferedReader;
|
import java.io.IOException;
|
import java.io.InputStream;
|
import java.io.InputStreamReader;
|
import java.net.InetAddress;
|
import java.net.UnknownHostException;
|
import java.text.SimpleDateFormat;
|
import java.util.Date;
|
|
/**
|
* 支付工具类
|
* @author pzb
|
* @Date 2022/11/28 21:10
|
*/
|
public class PayUtil {
|
|
|
/**
|
* 聚合支付预下单(微信、本行卡)
|
* @param subAppId 微信分配商户的子商户公众账号 ID
|
* @param openid 微信小程序openid
|
* @param chnlPayPage 微信商户号
|
* @param payType 支付类型:01-本行卡支付,02-聚合 微信,03-本行卡支付,微信支付 04-支付宝支付,05-本行卡支付,支付宝支付,06-微信支付,支付宝支付 07-全部
|
* @param amount 支付金额
|
* @param transDesc 交易描述
|
* @param backNotifyUrl 回调地址
|
* @param transSeq 商户流水号
|
* @param frontNotifyUrl 支付成功的跳转页面(前端)
|
* @param mcht_no 银行商户号
|
* @return
|
*/
|
public static String polymericPay(String subAppId, String openid, String chnlPayPage, String payType, Double amount, String transDesc, String backNotifyUrl, String transSeq, String frontNotifyUrl, String mcht_no){
|
String uri = "/api/conductor/cashier/polymericPay/1.0.0";
|
FopClient fopClient = DefaultFopClient.builder(Config.APP_ID, Config.PRIVATE_KEY, Config.FOP_PUBLIC_KEY)
|
.IsBodyEncrypt(true)
|
.SererUrl(Config.PRODUCTION_URL + uri)
|
.EncryptType(EncryptType.SM4)
|
.SignType(SignType.SM2).build();
|
|
/**
|
* model,request,response类
|
* 不同接口的model,request,response均不相同
|
* 其中,ConductorCashierXXXX需与apiUrl相互对应。在引入开放平台jar包后,驼峰可使用ide快捷键补全
|
* 或查看jar包中com.fop.sdk中的domain包,request包,response包,引入对象皆在此目录中
|
* 如,协议支付的model 为 ConductorCashierProtocolpaytransModel_100
|
*/
|
ConductorCashierPolymericpayModel_100 model = new ConductorCashierPolymericpayModel_100();
|
ConductorCashierPolymericpayRequest_100 request = new ConductorCashierPolymericpayRequest_100();
|
ConductorCashierPolymericpayResponse_100 response = null;
|
|
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMdd");
|
SimpleDateFormat sdf2 = new SimpleDateFormat("HHmmss");
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
|
String format = sdf1.format(new Date());
|
String format1 = sdf2.format(new Date());
|
model.setMchtNo(mcht_no);
|
model.setTransSeq(transSeq);
|
model.setTransDate(format);
|
model.setTransTime(format1);
|
model.setVersion("1.0");
|
model.setSndDt(format + format1);
|
|
model.setSubAppId(subAppId);//微信分配商户的子商户公众账号 ID
|
model.setOpenId(openid);//商户通过微信预授权获取的用户唯一标识,当payChnlType=02时必传
|
model.setChnlPayPage(chnlPayPage);//微信分配商户的子商户账号 ID,当 payChnlType=02 时必传
|
model.setPayChnlType(ToolUtil.isNotEmpty(openid) ? "02" : "01");//01-H5 02-微信小程序
|
model.setPayType(payType);//支付类型:01-本行卡支付,02-聚合 微信,03-本行卡支付,微信支付 04-支付宝支付,05-本行卡支付,支 付宝支付,06-微信支付,支付宝支 付 07-全部
|
model.setTransAmount(amount.toString());//交易金额
|
model.setTransDesc(transDesc);//交易描述
|
model.setBackNotifyUrl(backNotifyUrl);//后台异步通知回调地址
|
model.setFrontNotifyUrl(frontNotifyUrl);
|
try {
|
model.setTermIp(InetAddress.getLocalHost().getHostAddress());//终端IP
|
} catch (UnknownHostException e) {
|
e.printStackTrace();
|
}
|
request.setBizModel(model);
|
try {
|
response = fopClient.execute(request);
|
} catch (FopApiException e) {
|
e.printStackTrace();
|
}
|
System.err.println("预下单请求:" + JSON.toJSONString(model));
|
System.err.println("预下单响应:" + JSON.toJSONString(response));
|
if("00000000".equals(response.getBizCode()) || "88888888".equals(response.getBizCode())){
|
String transDate = response.getTransDate();
|
String transTime = response.getTransTime();
|
String transSeq1 = response.getTransSeq();
|
return response.getCodeUrl();
|
}else{
|
System.err.println(response.getBizCode() + ":" + response.getBizMsg());
|
}
|
return null;
|
}
|
|
|
/**
|
* 聚合支付交易状态查询
|
* @param oriTransSeq 原商户上送交易流水号
|
* @param oriTransDate 原交易日期
|
* @param oriTansTime 原交易时间
|
* @param oriTransAmount 原交易金额
|
* @return
|
*/
|
public static String poPayTransStatusQuery(String oriTransSeq, String oriTransDate, String oriTansTime, Double oriTransAmount){
|
String uri = "/api/conductor/cashier/poPayTransStatusQuery/1.0.0";
|
FopClient fopClient = DefaultFopClient.builder(Config.APP_ID, Config.PRIVATE_KEY, Config.FOP_PUBLIC_KEY)
|
.IsBodyEncrypt(true)
|
.SererUrl(Config.PRODUCTION_URL + uri)
|
.EncryptType(EncryptType.SM4)
|
.SignType(SignType.SM2).build();
|
|
/**
|
* model,request,response类
|
* 不同接口的model,request,response均不相同
|
* 其中,ConductorCashierXXXX需与apiUrl相互对应。在引入开放平台jar包后,驼峰可使用ide快捷键补全
|
* 或查看jar包中com.fop.sdk中的domain包,request包,response包,引入对象皆在此目录中
|
* 如,协议支付的model 为 ConductorCashierProtocolpaytransModel_100
|
*/
|
ConductorCashierPopaytransstatusqueryModel_100 model = new ConductorCashierPopaytransstatusqueryModel_100();
|
ConductorCashierPopaytransstatusqueryRequest_100 request = new ConductorCashierPopaytransstatusqueryRequest_100();
|
ConductorCashierPopaytransstatusqueryResponse_100 response = null;
|
|
model.setOriTransSeq(oriTransSeq);//原商户上送交易流水号
|
model.setOriTransType("mergePay.order");//sign.pay 协议支付,sign.deposit协议代付,sign.wx.jspay协议代付关联微信公众号支付,sign.ali.jspay协议代付关联支付宝服务窗支付,loan.pay欠款订单还款,card.prepay本行卡支付预下单,unified.pay客户被扫接口,ali.dynamic.code支付宝扫码支付,union.dynamic.code银联扫码支付,wx.jspay微信公众号支付,ali.jspay支付宝服务窗支付,mergePay.order聚合支付预下单
|
model.setOriTransDate(oriTransDate);//原交易日期
|
model.setOriTransTime(oriTansTime);//原交易时间
|
model.setOriTransAmount(oriTransAmount.toString());//原交易金额
|
request.setBizModel(model);
|
try {
|
response = fopClient.execute(request);
|
} catch (FopApiException e) {
|
e.printStackTrace();
|
}
|
return JSONObject.toJSONString(response);
|
}
|
|
|
/**
|
* 聚合支付退款
|
* @param oriTransSeq 原商户上送交易流水号
|
* @param oriTransDate 原交易日期
|
* @param oriTansTime 原交易时间
|
* @param oriTransAmount 原交易金额
|
* @param refundAmount 退款金额
|
* @return
|
*/
|
public static String polymericPayRefund(String oriTransSeq, String oriTransDate, String oriTansTime, Double oriTransAmount, Double refundAmount){
|
String uri = "/api/conductor/cashier/polymericPayRefund/1.0.0";
|
FopClient fopClient = DefaultFopClient.builder(Config.APP_ID, Config.PRIVATE_KEY, Config.FOP_PUBLIC_KEY)
|
.IsBodyEncrypt(true)
|
.SererUrl(Config.PRODUCTION_URL + uri)
|
.EncryptType(EncryptType.SM4)
|
.SignType(SignType.SM2).build();
|
|
/**
|
* model,request,response类
|
* 不同接口的model,request,response均不相同
|
* 其中,ConductorCashierXXXX需与apiUrl相互对应。在引入开放平台jar包后,驼峰可使用ide快捷键补全
|
* 或查看jar包中com.fop.sdk中的domain包,request包,response包,引入对象皆在此目录中
|
* 如,协议支付的model 为 ConductorCashierProtocolpaytransModel_100
|
*/
|
ConductorCashierPolymericpayrefundModel_100 model = new ConductorCashierPolymericpayrefundModel_100();
|
ConductorCashierPolymericpayrefundRequest_100 request = new ConductorCashierPolymericpayrefundRequest_100();
|
ConductorCashierPolymericpayrefundResponse_100 response = null;
|
|
model.setOriTransSeq(oriTransSeq);//原商户上送交易流水号
|
model.setOriTransType("mergePay.order");//sign.pay 协议支付,sign.deposit协议代付,sign.wx.jspay协议代付关联微信公众号支付,sign.ali.jspay协议代付关联支付宝服务窗支付,loan.pay欠款订单还款,card.prepay本行卡支付预下单,unified.pay客户被扫接口,ali.dynamic.code支付宝扫码支付,union.dynamic.code银联扫码支付,wx.jspay微信公众号支付,ali.jspay支付宝服务窗支付,mergePay.order聚合支付预下单
|
model.setOriTransDate(oriTransDate);//原交易日期
|
model.setOriTransTime(oriTansTime);//原交易时间
|
model.setOriTransAmount(oriTransAmount.toString());//原交易金额
|
model.setRefundAmount(refundAmount.toString());//退款金额
|
request.setBizModel(model);
|
try {
|
response = fopClient.execute(request);
|
} catch (FopApiException e) {
|
e.printStackTrace();
|
}
|
return JSONObject.toJSONString(response);
|
}
|
|
|
/**
|
* 协议代付关联支付宝服务窗支付
|
* @param chnlSeq 渠道流水号(自定义,唯一)
|
* @param signNum 签约协议号
|
* @param mchtReserve 商户保留内容,和签约上送一致
|
* @param buyerId 支付宝买家用户id
|
* @param body 商品描述
|
* @param totalFee 支付金额
|
* @param notifyUrl 通知回调地址
|
*/
|
public static void relatedZFBOfficialPay(String chnlSeq, String signNum, String mchtReserve, String buyerId, String body, String totalFee, String notifyUrl){
|
String uri = "/api/conductor/cashier/relatedZFBOfficialPay/1.0.0";
|
FopClient fopClient = DefaultFopClient.builder(Config.APP_ID, Config.PRIVATE_KEY, Config.FOP_PUBLIC_KEY)
|
.IsBodyEncrypt(true)
|
.SererUrl(Config.PRODUCTION_URL + uri)
|
.EncryptType(EncryptType.SM4)
|
.SignType(SignType.SM2).build();
|
|
/**
|
* model,request,response类
|
* 不同接口的model,request,response均不相同
|
* 其中,ConductorCashierXXXX需与apiUrl相互对应。在引入开放平台jar包后,驼峰可使用ide快捷键补全
|
* 或查看jar包中com.fop.sdk中的domain包,request包,response包,引入对象皆在此目录中
|
* 如,协议支付的model 为 ConductorCashierProtocolpaytransModel_100
|
*/
|
ConductorCashierRelatedzfbofficialpayModel_100 model = new ConductorCashierRelatedzfbofficialpayModel_100();
|
ConductorCashierRelatedzfbofficialpayRequest_100 request = new ConductorCashierRelatedzfbofficialpayRequest_100();
|
ConductorCashierRelatedzfbofficialpayResponse_100 response = null;
|
|
Date date = new Date();
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
|
SimpleDateFormat sdf1 = new SimpleDateFormat("HHmmss");
|
|
model.setChnlSeq(chnlSeq);//渠道流水号
|
model.setChnlDate(sdf.format(date));//渠道日期
|
model.setChnlTime(sdf1.format(date));//渠道时间
|
model.setSignNum(signNum);//签约协议号
|
model.setMchtReserve(mchtReserve);//商户保留 即在协议签约时,上送的商户保留字段,普通商户一般为用户标识号,需要确保唯一
|
model.setDeviceInfo("");//设备号
|
model.setBuyerId(buyerId);//卖价支付宝用户ID
|
model.setBody(body);//商品描述
|
model.setTotalFee(totalFee);//支付总金额
|
try {
|
model.setTermIp(InetAddress.getLocalHost().getHostAddress());//终端IP
|
} catch (UnknownHostException e) {
|
e.printStackTrace();
|
}
|
model.setTermMac("");//终端MAC信息
|
model.setLocations("");//经纬度信息
|
model.setNotifyUrl(notifyUrl);//通知回调地址
|
request.setBizModel(model);
|
try {
|
response = fopClient.execute(request);
|
} catch (FopApiException e) {
|
e.printStackTrace();
|
}
|
if("00000000".equals(response.getBizCode())){
|
if("00".equals(response.getCode())){
|
String tradeMoney = response.getTradeMoney();//实际支付金额
|
String totalFee1 = response.getTotalFee();//订单金额
|
String tradeNo = response.getTradeNo();//支付宝JS订单号
|
}else{
|
System.err.println(response.getMsg());
|
}
|
|
String transDate = response.getTransDate();
|
String transTime = response.getTransTime();
|
String transSeq1 = response.getTransSeq();
|
|
}else{
|
System.err.println(response.getBizMsg());
|
}
|
|
}
|
|
|
|
|
|
|
/**
|
* 支付宝扫码支付
|
* @param chnlSeq
|
* @param deviceInfo
|
* @param body
|
* @param totalFee
|
* @param subject
|
* @param notifyUrl
|
* @return
|
*/
|
public static String zfbScanCodePay(String chnlSeq, String deviceInfo, String body, Double totalFee, String subject, String notifyUrl){
|
String uri = "/api/conductor/cashier/zfbScanCodePay/1.0.0";
|
FopClient fopClient = DefaultFopClient.builder(Config.APP_ID, Config.PRIVATE_KEY, Config.FOP_PUBLIC_KEY)
|
.IsBodyEncrypt(true)
|
.SererUrl(Config.PRODUCTION_URL + uri)
|
.EncryptType(EncryptType.SM4)
|
.SignType(SignType.SM2).build();
|
|
/**
|
* model,request,response类
|
* 不同接口的model,request,response均不相同
|
* 其中,ConductorCashierXXXX需与apiUrl相互对应。在引入开放平台jar包后,驼峰可使用ide快捷键补全
|
* 或查看jar包中com.fop.sdk中的domain包,request包,response包,引入对象皆在此目录中
|
* 如,协议支付的model 为 ConductorCashierProtocolpaytransModel_100
|
*/
|
ConductorCashierZfbscancodepayModel_100 model = new ConductorCashierZfbscancodepayModel_100();
|
ConductorCashierZfbscancodepayRequest_100 request = new ConductorCashierZfbscancodepayRequest_100();
|
ConductorCashierZfbscancodepayResponse_100 response = null;
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HHmmss");
|
String format = sdf.format(new Date());
|
model.setChnlSeq(chnlSeq);//渠道流水号
|
model.setChnlDate(format.split(" ")[0]);//渠道日期
|
model.setChnlTime(format.split(" ")[1]);//渠道时间
|
model.setDeviceInfo(deviceInfo);//设备号
|
model.setBody(body);//商品描述
|
model.setFeeType("CNY");//货币类型
|
model.setTotalFee(totalFee.toString());//总金额
|
model.setSubject(subject);//订单标题
|
try {
|
model.setTermIp(InetAddress.getLocalHost().getHostAddress());//终端IP
|
model.setTermMac("");//终端MAC信息
|
model.setLocations("");//经纬度信息
|
} catch (UnknownHostException e) {
|
e.printStackTrace();
|
}
|
model.setNotifyUrl(notifyUrl);//异步通知回调地址
|
request.setBizModel(model);
|
try {
|
response = fopClient.execute(request);
|
} catch (FopApiException e) {
|
e.printStackTrace();
|
}
|
if("00000000".equals(response.getBizCode())){
|
if("00".equals(response.getResultCode())){//成功
|
return response.getCodeUrl();
|
}else{
|
System.err.println(response.getResultMsg());
|
return null;
|
}
|
}else{
|
System.err.println(response.getBizMsg());
|
return null;
|
}
|
}
|
|
|
|
|
/**
|
* 支付回调处理
|
* @param request
|
* @return
|
*/
|
public static ResultNotification payResultNotification(HttpServletRequest request){
|
String param = null;
|
try {
|
param = getParam(request);
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
JSONObject jsonObject1 = JSON.parseObject(param);
|
JSONObject jsonObject = FopClient.SM2checkSign(jsonObject1, Config.FOP_PUBLIC_KEY);
|
if(!jsonObject.getBoolean("sign")){
|
System.err.println("线下收款回调异常---------->" + jsonObject.getString("msg"));
|
return null;
|
}
|
ResultNotification resultNotification = jsonObject1.toJavaObject(ResultNotification.class);
|
resultNotification.setResponseStr("success");//响应内容
|
return resultNotification;
|
}
|
|
|
|
/**
|
* 获取请求内容
|
* @param request
|
* @return
|
* @throws IOException
|
*/
|
private static String getParam(HttpServletRequest request) throws IOException {
|
// 读取参数
|
InputStream inputStream;
|
StringBuilder sb = new StringBuilder();
|
inputStream = request.getInputStream();
|
String s;
|
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
|
while ((s = in.readLine()) != null) {
|
sb.append(s);
|
}
|
in.close();
|
inputStream.close();
|
return sb.toString();
|
}
|
|
|
public static void main(String[] args) {
|
// String polymericPay = PayUtil.polymericPay(null, null, null, "02", 0.01d, "测试支付", "https://10pz685243.zicp.fun/user/base/offlineTravelPaymentCallback", "123111");
|
// System.err.println(polymericPay);
|
// PayUtil.relatedZFBOfficialPay("11212", "", "", "1212", "测试商品", "0.01", "");
|
}
|
}
|