package cc.mrbird.febs.pay.service.impl;
|
|
import cc.mrbird.febs.mall.entity.MallOrderInfo;
|
import cc.mrbird.febs.mall.mapper.MallOrderInfoMapper;
|
import cc.mrbird.febs.pay.model.*;
|
import cc.mrbird.febs.pay.service.UnipayService;
|
import cc.mrbird.febs.pay.util.*;
|
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.json.JSONUtil;
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONObject;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.codec.digest.DigestUtils;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.io.IOException;
|
import java.lang.reflect.Field;
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.text.DecimalFormat;
|
import java.util.*;
|
|
@Slf4j
|
@Service
|
public class UnipayServiceImpl implements UnipayService {
|
|
//汇聚支付平台公钥
|
public static final String platformPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwSAEXsiC0IYh" +
|
"a6a94imKq8VfOkk7WjDRAQWMBRnoKOZeEUeMrHYiblcrqeMYXGpV13288iUOkuyKwkPXkYXyIQK8emvJIbQOhtB5bS" +
|
"lAbodsPgncM9Ney1GFiz+7ogBxyt58mP8AA9UHtMw7u78zZoQ1+dUWwUUowVXml3Q0cVQIDAQAB";
|
//本地生成的公钥
|
public static final String paySecretKey =
|
"MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJSsoLHAy4P+H76l4i6IMZ/JKKTVphvrJBSB777N8h" +
|
"gzN38M+66IqazRQLNjjyn2UZxm4eSfuJ4OBxCTGLJgDOw8B9l9lVo+0bzhNxsy5ae20EOlQa3h8xfCjCCU" +
|
"Xb8VP8yknG43Wk1WtwLX5VYWmJFTwA1I0dWQR4RlbHH2q2aVAgMBAAECgYBZNyoK4JV/tFwaTHLo12Nn7g" +
|
"9MssRGFpmFEN/sEKuJKBrSS9kvx+SBxuPbgg/j72LTxs0hI1NmzSYiJRL53zeBFM0wM2/D2zW0pZfogUPN" +
|
"7Mb3FkFOoE0CxFwn7pjjBkvAsZQJS2fZFY6cf/WYhVI+XCMzjiQWJSQUXKEfWzUflQJBAMpLzinyAsBHKe" +
|
"6lmAkSh/yaQX76cnxNZGmfc/gj62qM5YDzpt3+Za5Y4NSq5kYu36NAgorf2ipJPRwpgS13fK8CQQC8JKVP" +
|
"2YgZ39fa+xVJu3yTT48k9EnYIEfsv/Bc7AVdpaZKDeEBuGpBb0JQzuIg3Zd6yNQCzH3oBqp8l6l/fgn7Ak" +
|
"EAtFluvHB4yWjoVk0lRPlTaP0w5P5ssKrimVPBtPh4+a4RMayHGKSjjBLKpm6SCwHg+Q8bEqpNOqO+qmvK" +
|
"MXm0GwJAZd4Bk8ZYJopIOUyRLibRQIFnI78Q7HAuAUW7QtSX4yh5bMcu+Nt8zIkNAuvBC8Ju7hAmmo1V7n" +
|
"cNgAAtydXYWQJALLOFCjCkRgeRVL8YE8bVi4U16b8ltAN1DlbWEzui6VFy2vIga3IryesNVAOOdornyAwf" +
|
"1huqB2lYfuQwtrIBKg==";
|
public static final String MD5KEY = "2e95f6a3e11e47fa8a4386d6aefe1735";
|
public static final String notifyUrl = "http://47.111.90.145:8800/api/unipay/unipayCallBack";
|
public static final String agreementPayNotifyUrl = "http://47.111.90.145:8800/api/unipay/agreeMentPayCallBack";
|
public static final String singlePayNotifyUrl = "http://47.111.90.145:8800/api/unipay/singlePayCallBack";
|
public static final String p1MerchantNo = "888118000001971";/** 商户编号 */
|
public static final String aesKey = "1234567891234567";/** 商户编号 */
|
|
@Autowired
|
private MallOrderInfoMapper orderInfoMapper;
|
|
@Override
|
@Transactional
|
public String unipay(UnipayDto unipayDto) {
|
String key = "2e95f6a3e11e47fa8a4386d6aefe1735";/** md5密钥商户后台-商户中心-商户设置-密钥管理获取 必填!*/
|
Map<String, String> map = new HashMap<String, String>();
|
map.put("p0_Version", "1.0");/** 版本号 */
|
map.put("p1_MerchantNo", p1MerchantNo);/** 商户编号 */
|
map.put("p2_OrderNo", unipayDto.getOrderNo()); /**商户订单号*/
|
map.put("p3_Amount", unipayDto.getAmount().toString());/**订单金额*/
|
map.put("p4_Cur", "1"); /**交易币种 */
|
map.put("p5_ProductName", unipayDto.getProductName()); /** 商品名称 */
|
map.put("p9_NotifyUrl", notifyUrl); /** 服务器异步通知地址 */
|
map.put("q1_FrpCode", unipayDto.getFrpCode()); /** 交易类型*/
|
map.put("qa_TradeMerchantNo",unipayDto.getTradeMerchantNo()); /** 777开头的报备商户号 必填!*/
|
map.put("q7_AppId", "wx42ce0fbc27965fe9"); /** 777开头的报备商户号 必填!*/
|
|
String Strmap = createLinkStringByGet(map);
|
// 签名
|
String sign = "";
|
sign = SignByMD5(Strmap, key);
|
map.put("hmac", sign);/** 签名数据 */
|
System.out.println("发送:" + JSON.toJSONString(map).toString());
|
|
// post请求参数内容
|
HttpRequester hr = new HttpRequester();
|
HttpRespons HP = null;
|
try {
|
HP = hr.sendPost("https://www.joinpay.com/trade/uniPayApi.action", map);
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
System.out.println("接收返回参数:" + HP.getContent());
|
Boolean result = false;
|
try {
|
result = nosign(HP.getContent(), key);
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
if(result){
|
return HP.getContent();
|
}else{
|
return "fail";
|
}
|
}
|
|
|
//参数的拼接整理
|
private String createLinkStringByGet(Map<String, String> params){
|
// TODO Auto-generated method stub
|
List<String> keys = new ArrayList<String>(params.keySet());
|
Collections.sort(keys);
|
String str1 ="";
|
for(int i=0;i<keys.size();i++) {
|
String key = keys.get(i);
|
|
Object value = params.get(key);//(String) 强制类型转换
|
if(value instanceof Integer) {
|
value = (Integer)value;
|
}
|
if(i==keys.size()-1) {
|
|
str1 = str1+value.toString();
|
}else {
|
|
str1 = str1+value;
|
}
|
}
|
System.out.println("整理"+str1);
|
return str1;
|
}
|
|
/**
|
* MD5签名
|
*
|
* @param requestSign 请求签名串
|
* @param merchantKey 商户秘钥
|
*/
|
private String SignByMD5(String requestSign, String merchantKey) {
|
|
String reqHmac = "";
|
try {
|
reqHmac = DigestUtils.md5Hex(requestSign + merchantKey).toUpperCase();
|
} catch (Exception e) {}
|
|
return reqHmac;
|
}
|
|
/**
|
* 验证返回参数
|
* @param hp
|
* @param key
|
* @return
|
* @throws Exception
|
*/
|
private boolean nosign(String hp, String key){
|
System.out.println("接收到:" + hp);
|
JSONObject myJson = JSONObject.parseObject(hp);
|
Map m = myJson;
|
|
// 返回hmac
|
String returnHmac = (String) m.remove("hmac");
|
System.out.println(m.toString());
|
String Strmap = createLinkStringByGet(m);
|
|
// 返回参数组装hmac
|
String hmac1 = SignByMD5(Strmap, key);
|
return hmac1.equalsIgnoreCase(returnHmac);
|
|
}
|
|
|
|
@Override
|
@Transactional
|
public String agreementPay(AgreementPayDto agreementPayDto) {
|
|
String secretKey =paySecretKey;
|
String key = aesKey;//敏感信息加密key
|
|
Map<String, Object> map = new HashMap<>();
|
RequestParam requestParam = new RequestParam();
|
requestParam.setMch_no(p1MerchantNo);// 商户编号
|
requestParam.setMethod("fastPay.agreement.pay");// 固定方法名
|
requestParam.setVersion("1.0");// 版本号
|
requestParam.setRand_str("12345678901234567890123456789012");// 随机字符串
|
requestParam.setSign_type("2");// 签名类型
|
try {
|
requestParam.setSec_key(RSAUtil.encryptByPublicKey(platformPublicKey,aesKey));//加密密钥
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
|
map.put("mch_order_no",agreementPayDto.getOrderNo()); // 商户订单号
|
map.put("order_amount", agreementPayDto.getOrderAmount()); // 订单金额;金额保留两位小数
|
map.put("mch_req_time", agreementPayDto.getOrderTime()); // 订单时间
|
map.put("order_desc", agreementPayDto.getOrderDesc()); // 商品名称
|
map.put("callback_url", agreementPayNotifyUrl); // 异步通知地址
|
map.put("bank_card_no", AESUtil.Aes256Encode(agreementPayDto.getBankNo(),aesKey)); // 签约银行卡号
|
|
requestParam.setData(JsonUtil.toString(map));
|
|
String signStr = null;
|
try {
|
signStr = getSortedString(requestParam);
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
System.out.println("待签名字符串:"+signStr);// 待签名字符串
|
|
// 签名
|
if (SignTypeEnum.RSA.getValue().equals(requestParam.getSign_type())) {
|
try {
|
signStr =(RSAUtil.sign(signStr, secretKey, false));
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
} else {
|
signStr = "";
|
System.out.println("未预期的签名类型:" + requestParam.getSign_type());
|
}
|
requestParam.setSign(signStr);
|
|
// Map转json字符串
|
String reqBodyJson = JSON.toJSONString(requestParam);
|
System.out.println(reqBodyJson);
|
String httpResponseJson = null;
|
try {
|
httpResponseJson = HttpClientUtil.sendHttpPost("https://api.joinpay.com/fastpay", reqBodyJson);
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
System.out.println(httpResponseJson);
|
|
if(StrUtil.isNotBlank(httpResponseJson)){
|
return httpResponseJson;
|
}else{
|
return "fail";
|
}
|
}
|
|
@Override
|
@Transactional
|
public String singlePay(SinglePayDto singlePayDto) {
|
String singlePay = null;
|
String key = MD5KEY;
|
|
Map<String, Object> map = new HashMap<>();
|
map.put("userNo", p1MerchantNo);// 商户编号
|
map.put("productCode", "BANK_PAY_DAILY_ORDER");//产品类型
|
map.put("requestTime", DateUtil.now()); // 交易请求时间
|
map.put("merchantOrderNo", singlePayDto.getMerchantOrderNo());//商户订单号
|
map.put("receiverAccountNoEnc", singlePayDto.getReceiverAccountNoEncBankNo()); // 收款账户号
|
map.put("receiverNameEnc", singlePayDto.getReceiverAccountNoEncName()); // 收款人
|
map.put("receiverAccountType", singlePayDto.getReceiverAccountType());//账户类型
|
map.put("paidAmount", singlePayDto.getPaidAmount()); //交易金额
|
map.put("currency", singlePayDto.getCurrency());//币种
|
map.put("isChecked", singlePayDto.getIsChecked());//是否复核
|
map.put("paidDesc", singlePayDto.getPaidDesc());//代付说明
|
map.put("paidUse", singlePayDto.getPaidUse());//代付用途
|
map.put("callbackUrl", singlePayNotifyUrl);//商户通知地址
|
|
String reqSign = getRequestSign(map);
|
// 签名
|
String hmac = Md5_Sign.SignByMD5(reqSign, key);
|
map.put("hmac", hmac);/** 签名数据 */
|
|
// Map转json字符串
|
String reqBodyJson = JSON.toJSONString(map);
|
System.out.println("reqBodyJson:" + reqBodyJson);
|
String httpResponseJson = null;
|
try {
|
httpResponseJson = HttpClientUtil
|
.sendHttpPost("https://www.joinpay.com/payment/pay/singlePay",reqBodyJson);
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
System.out.println(httpResponseJson);
|
if(StrUtil.isNotBlank(httpResponseJson)){
|
try {
|
singlePay = doResponseInfo(httpResponseJson, key);
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
return singlePay;
|
}else{
|
return "fail";
|
}
|
}
|
|
/**
|
* 对单笔代付响应信息的处理
|
*
|
* @param httpResponseJson 响应信息json字符串
|
* @param key 商户秘钥
|
* @throws Exception 异常实体类
|
*/
|
@SuppressWarnings("unchecked")
|
private static String doResponseInfo(String httpResponseJson, String key) throws Exception {
|
// 响应信息map集合
|
Map<String, Object> httpResponseMap = (Map<String, Object>) JSONObject.parse(httpResponseJson);
|
// 业务数据map集合
|
Map<String, Object> dataMap = (Map<String, Object>) httpResponseMap.get("data");
|
dataMap.put("statusCode", httpResponseMap.get("statusCode"));
|
dataMap.put("message", httpResponseMap.get("message"));
|
|
// 请求签名串
|
String reqSign = getRequestSign(httpResponseMap);
|
// 响应签名串
|
String respSign = getResponseSign(dataMap);
|
// 请求数据的加密签名
|
String reqHmac = Md5_Sign.SignByMD5(respSign, key);
|
// 请求数据的加密签名
|
String respHmac = (String) dataMap.get("hmac");
|
System.out.println("reqHmac:" + reqHmac);
|
System.out.println("respSign:" + respHmac);
|
|
reqHmac=reqHmac.toUpperCase();
|
respHmac=respHmac.toUpperCase();
|
boolean isMatch = reqHmac.equals(respHmac);
|
if (isMatch) {
|
if("2001".equals(httpResponseMap.get("statusCode").toString())
|
&& ObjectUtil.isEmpty(dataMap.get("errorCode"))){
|
System.out.println("验签成功");
|
return dataMap.get("merchantOrderNo").toString();
|
}
|
}
|
return "fail";
|
}
|
|
/**
|
* 获取响应数据签名串信息
|
* 必须按新代付接口文档应答参数信息顺序来进行字符串的拼接,详情请参考新代付接口文档的应答报文
|
*
|
* @param params 响应数据参数
|
* @return 返回响应签名串
|
*/
|
public static String getResponseSign(Map<String, Object> params) {
|
|
StringBuilder stringBuilder = new StringBuilder();
|
stringBuilder.append(params.get("statusCode")).append(params.get("message")).append(params.get("errorCode"))
|
.append(params.get("errorDesc")).append(params.get("userNo")).append(params.get("merchantOrderNo"));
|
|
return stringBuilder.toString();
|
}
|
|
/**
|
* 获取请求数据签名串信息
|
* 必须按新代付接口文档请求参数信息顺序来进行字符串的拼接,详情请参考新代付接口文档请求报文
|
*
|
* @param params 请求数据参数
|
* @return 返回请求签名串
|
*/
|
public static String getRequestSign(Map<String, Object> params) {
|
|
StringBuilder stringBuilder = new StringBuilder();
|
stringBuilder.append(params.get("userNo"))
|
.append(params.get("productCode"))
|
.append(params.get("requestTime"))
|
.append(params.get("merchantOrderNo"))
|
.append(params.get("receiverAccountNoEnc"))
|
.append(params.get("receiverNameEnc"))
|
.append(params.get("receiverAccountType"))
|
.append(params.get("paidAmount"))
|
.append(params.get("currency"))
|
.append(params.get("isChecked"))
|
.append(params.get("paidDesc"))
|
.append(params.get("paidUse"))
|
.append(params.get("callbackUrl"));
|
System.out.println("reqSign:" + stringBuilder.toString());
|
return stringBuilder.toString();
|
}
|
|
public static void main(String[] args) {
|
// BigDecimal value = new BigDecimal("0.10858").setScale(2,BigDecimal.ROUND_HALF_UP);
|
BigDecimal value = new BigDecimal("1231.1").setScale(2, BigDecimal.ROUND_DOWN);
|
DecimalFormat decimalFormat = new DecimalFormat("0.00#");
|
String strVal = decimalFormat.format(value);
|
System.out.println(strVal);
|
}
|
|
@Override
|
public String getAgreeMentPaySms(AgreeMentPaySmsDto agreeMentPaySmsDto) {
|
String secretKey = paySecretKey;
|
|
Map<String, Object> map = new HashMap<>();
|
RequestParam requestParam = new RequestParam();
|
requestParam.setMch_no(p1MerchantNo);// 商户编号
|
requestParam.setMethod("fastPay.agreement.signSms");// 固定方法名
|
requestParam.setVersion("1.0");// 版本号
|
requestParam.setRand_str("12345678901234567890123456789012");// 随机字符串
|
requestParam.setSign_type("2");// 签名类型
|
try {
|
requestParam.setSec_key(RSAUtil.encryptByPublicKey(platformPublicKey,aesKey));//加密密钥
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
|
|
MallOrderInfo orderInfo = orderInfoMapper.selectByOrderNo(agreeMentPaySmsDto.getOrderNo());
|
map.put("mch_order_no", "NO_"+orderInfo.getOrderNo()); // 商户订单号
|
|
BigDecimal value = orderInfo.getAmount().setScale(2, BigDecimal.ROUND_DOWN);
|
DecimalFormat decimalFormat = new DecimalFormat("0.00#");
|
String strVal = decimalFormat.format(value);
|
map.put("order_amount", strVal); // 订单金额
|
map.put("mch_req_time", DateUtil.now()); // 下单时间
|
map.put("payer_name",AESUtil.Aes256Encode(agreeMentPaySmsDto.getName(),aesKey)); // 姓名
|
map.put("id_type", agreeMentPaySmsDto.getIdType()); // 证件类型
|
map.put("id_no", AESUtil.Aes256Encode(agreeMentPaySmsDto.getIdCardNum(),aesKey)); // 证件号码
|
map.put("bank_card_no", AESUtil.Aes256Encode(agreeMentPaySmsDto.getBankNo(),aesKey)); // 银行卡号
|
map.put("mobile_no", AESUtil.Aes256Encode(agreeMentPaySmsDto.getPhone(), aesKey)); // 手机号
|
|
requestParam.setData(JsonUtil.toString(map));
|
|
String signStr = null;
|
try {
|
signStr = getSortedString(requestParam);
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
System.out.println("待签名字符串:"+signStr);// 待签名字符串
|
|
// 签名
|
if (SignTypeEnum.RSA.getValue().equals(requestParam.getSign_type())) {
|
try {
|
signStr =(RSAUtil.sign(signStr, secretKey, false));
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
} else {
|
signStr = "";
|
System.out.println("未预期的签名类型:" + requestParam.getSign_type());
|
}
|
requestParam.setSign(signStr);
|
|
|
// Map转json字符串
|
String reqBodyJson = JSON.toJSONString(requestParam);
|
System.out.println(reqBodyJson);
|
String httpResponseJson = null;
|
try {
|
httpResponseJson = HttpClientUtil.sendHttpPost("https://api.joinpay.com/fastpay", reqBodyJson);
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
System.out.println(httpResponseJson);
|
cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(httpResponseJson);
|
System.out.println(jsonObject);
|
String biz_code = jsonObject.get("biz_code").toString();
|
String biz_msg = jsonObject.get("biz_msg").toString();
|
if("JS000000".equals(biz_code)){
|
return biz_code;
|
}else{
|
return biz_msg;
|
}
|
}
|
|
@Override
|
public String agreementSign(AgreementSignDto agreementSignDto) {
|
String secretKey = paySecretKey;
|
|
Map<String, Object> map = new HashMap<>();
|
RequestParam requestParam = new RequestParam();
|
requestParam.setMch_no(p1MerchantNo);// 商户编号
|
requestParam.setMethod("fastPay.agreement.smsSign");// 固定方法名
|
requestParam.setVersion("1.0");// 版本号
|
requestParam.setRand_str("12345678901234567890123456789012");// 随机字符串
|
requestParam.setSign_type("2");// 签名类型
|
try {
|
requestParam.setSec_key(RSAUtil.encryptByPublicKey(platformPublicKey,aesKey));
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
|
map.put("mch_order_no", "NO_"+agreementSignDto.getOrderNo()); // 商户订单号
|
map.put("sms_code", agreementSignDto.getSmsCode()); // 签约短信验证码
|
|
requestParam.setData(JsonUtil.toString(map));
|
|
String signStr = null;
|
try {
|
signStr = getSortedString(requestParam);
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
System.out.println(signStr);// 待签名字符串
|
|
// 签名
|
if (SignTypeEnum.RSA.getValue().equals(requestParam.getSign_type())) {
|
try {
|
signStr =(RSAUtil.sign(signStr, secretKey, false));
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
} else {
|
signStr = "";
|
System.out.println("未预期的签名类型:" + requestParam.getSign_type());
|
}
|
requestParam.setSign(signStr);
|
|
|
// Map转json字符串
|
String reqBodyJson = JSON.toJSONString(requestParam);
|
System.out.println(reqBodyJson);
|
String httpResponseJson = null;
|
try {
|
httpResponseJson = HttpClientUtil.sendHttpPost("https://api.joinpay.com/fastpay", reqBodyJson);
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
System.out.println(httpResponseJson);
|
|
if(StrUtil.isNotBlank(httpResponseJson)){
|
return httpResponseJson;
|
}else{
|
return "fail";
|
}
|
}
|
|
protected static String getSortedString(Object obj) throws Exception {
|
Field[] fields = obj.getClass().getDeclaredFields();
|
|
Map<String, String> map = new HashMap<String, String>();
|
for (int i = 0; i < fields.length; i++) {
|
Field filed = fields[i];
|
String name = filed.getName();
|
if (SignUtil.NOT_SIGN_PARAM.contains(name)) {// 不参与签名或验签的参数直接跳过
|
continue;
|
}
|
filed.setAccessible(true);
|
map.put(name, String.valueOf(filed.get(obj)));
|
}
|
StringBuffer content = new StringBuffer();
|
List<String> keys = new ArrayList(map.keySet());
|
Collections.sort(keys); // 排序map
|
for (int i = 0; i < keys.size(); i++) {
|
String key = keys.get(i);
|
String value = map.get(key);
|
|
if (i != 0) {
|
content.append(SignUtil.SIGN_SEPARATOR);
|
}
|
content.append(key).append(SignUtil.SIGN_EQUAL).append(value);
|
}
|
return content.toString();
|
}
|
|
}
|