汇聚支付
实现
配置信息
joinpay:
# 商户编号
user-no:
# 报备商户号
report-user-no:
# 商户MD5签名密钥
private-key:
# 产品类型
product-code:
# 是否复核
is-checked:
# 回调通知地址
callback-url:
#代付用途
paid-use:
# 支付回调
notifyUrl:
# 退款回调
refundNotifyUrl:
# 代付回调
paidNotifyUrl:
@Data
@Configuration
@ConfigurationProperties(prefix = "joinpay")
public class JoinPayConfig {
private String userNo;
private String reportUserNo;
private String productCode;
private String isChecked;
private String callbackUrl;
private String paidUse;
private String privateKey;
private String notifyUrl;
private String refundNotifyUrl;
private String paidNotifyUrl;
}
工具类
MD5签名&验签
public class Md5_Sign {
public static String SignByMD5(String requestSign, String merchantKey) {
String reqHmac = "";
try {
reqHmac = DigestUtils.md5Hex(requestSign + merchantKey).toUpperCase();
} catch (Exception e) {}
return reqHmac;
}
}
post请求
public class HttpClientUtil {
public static String sendHttpPost(String url, String body) throws Exception {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader("Content-Type","application/json;charset=UTF-8");
StringEntity setEntity = new StringEntity(body,"utf-8");
setEntity.setContentType("application/json");
setEntity.setContentEncoding("UTF-8");
httpPost.setEntity(setEntity);
CloseableHttpResponse response = httpClient.execute(httpPost);
System.out.println(response.getStatusLine().getStatusCode() + "\n");
HttpEntity entity = response.getEntity();
String responseContent = EntityUtils.toString(entity, "UTF-8");
System.out.println(responseContent);
response.close();
httpClient.close();
return responseContent;
}
}
工具方法
//验签
private static boolean nosign(String hp, String key) throws Exception {
System.out.println("接收到:" + hp);
JSONObject myJson = JSONObject.parseObject(hp);
Map m = myJson;
// 返回hmac
String returnHmac = (String) m.remove("hmac");
String Strmap = CreateLinkStringByGet1.createLinkStringByGet(m);
// 返回参数组装hmac
String hmac1 = Md5_Sign.SignByMD5(Strmap, key);
return hmac1.equalsIgnoreCase(returnHmac);
}
//获取请求体
public String getRequestBody(HttpServletRequest request) throws IOException {
StringBuilder sb = new StringBuilder();
String line;
try (BufferedReader reader = request.getReader()) {
while ((line = reader.readLine()) != null) {
sb.append(line);
}
}
return sb.toString();
}
//获取请求参数
public Map<String, String> getRequestParamsAsMap(HttpServletRequest request) {
// 1. 创建一个新的 HashMap 用于存储结果
Map<String, String> paramMap = new HashMap<>();
// 2. 获取请求参数的 Map<String, String[]>
Map<String, String[]> requestParams = request.getParameterMap();
// 3. 遍历 requestParams 并转换到 paramMap
requestParams.forEach((name, values) -> {
// 对于每个参数名 (name),它的值是一个字符串数组 (values)
// 我们通常取数组的第一个元素作为参数的值
if (values != null && values.length > 0) {
paramMap.put(name, values[0]);
} else {
paramMap.put(name, null); // 或者空字符串 ""
}
});
// 4. 返回转换后的 Map
return paramMap;
}
//签名
public static String singlePayGetResponseSign(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();
}
//....
支付&支付回调
//支付接口
public JSONObject uniPay(String orderNumber, BigDecimal orderPrice, String goodsName, String miniOpenid) throws Exception {
String key = joinPayConfig.getPrivateKey();
Map<String, String> map = new HashMap<String, String>();
map.put("p0_Version", "2.6");// 版本号
map.put("p1_MerchantNo", joinPayConfig.getUserNo());// 商户编号
map.put("p2_OrderNo", orderNumber); // 商户订单号
map.put("p3_Amount", String.valueOf(orderPrice));//订单金额
map.put("p4_Cur", "1"); //交易币种,人民币1
map.put("p5_ProductName", goodsName); // 商品名称
map.put("p6_ProductDesc", "");
map.put("p9_NotifyUrl", joinPayConfig.getNotifyUrl()); // 服务器异步通知地址
map.put("q1_FrpCode", "WEIXIN_XCX"); // 交易类型
map.put("q5_OpenId", miniOpenid); // openid
map.put("q7_AppId", wechatPayConfig.getAppId()); // appid
map.put("qa_TradeMerchantNo", joinPayConfig.getReportUserNo()); // 报备商户号
map.put("qi_FqSellerPercen", "0");
String Strmap = CreateLinkStringByGet1.createLinkStringByGet(map);
// 签名
String sign = "";
sign = Md5_Sign.SignByMD5(Strmap, key);
map.put("hmac", sign);/** 签名数据 */
System.out.println("发送:" + JSON.toJSONString(map).toString());
// post请求参数内容
StringBuffer param = new StringBuffer();
for (String k : map.keySet()) {
param.append("&");
param.append(k).append("=").append(map.get(k));
}
HttpResponse response = HttpRequest.post("https://trade.joinpay.com/tradeRt/uniPay")
.header("Content-Type", "application/x-www-form-urlencoded")
.body(param.toString())
.execute();
System.out.println("接收返回参数:" + response.body());
boolean yesorno = nosign(response.body(), key);
if (yesorno) {
System.out.println("支付验签成功");
JSONObject jsonObject = JSONObject.parseObject(response.body());
return jsonObject.getJSONObject("rc_Result");
} else {
System.out.println("支付验签失败");
}
return new JSONObject();
}
//支付回调
public void payNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
String key = joinPayConfig.getPrivateKey();
response.setContentType("text/plain;charset=utf-8");
response.setCharacterEncoding("utf-8");
try {
Map<String, String> requestParamsAsMap = getRequestParamsAsMap(request);
String r2_OrderNo = requestParamsAsMap.get("r2_OrderNo");
Map<String, String> map = new HashMap<String, String>();
map.put("p0_Version", "2.6");/** 版本号 */
map.put("p1_MerchantNo", joinPayConfig.getUserNo());/** 商户编号 */
map.put("p2_OrderNo", r2_OrderNo); /**商户订单号*/
String Strmap = CreateLinkStringByGet1.createLinkStringByGet(map);
// 签名
String sign = "";
sign = Md5_Sign.SignByMD5(Strmap, key);
map.put("hmac", sign);/** 签名数据 */
System.out.println("查询订单状态发送:" + JSON.toJSONString(map).toString());
// post请求参数内容
StringBuffer param = new StringBuffer();
for (String k : map.keySet()) {
param.append("&");
param.append(k).append("=").append(map.get(k));
}
HttpResponse resp = HttpRequest.post("https://trade.joinpay.com/tradeRt/queryOrder")
.header("Content-Type", "application/x-www-form-urlencoded")
.body(param.toString())
.execute();
System.out.println("接收返回参数:" + resp.body());
boolean yesorno = nosign(resp.body(), key);
if (yesorno) {
JSONObject resData = JSONObject.parseObject(resp.body());
Map mp = resData;
if(mp.get("ra_Status").equals("100")){
response.setStatus(200);
response.getWriter().write("success");
response.getWriter().flush();
response.getWriter().close();
}
} else {
System.out.println("订单查询验签失败");
}
} catch (Exception e) {
log.error("支付回调处理失败:" + e.getMessage());
response.setStatus(500);
response.getWriter().flush();
response.getWriter().close();
}
}
退款&退款回调
//退款
public String refund(String orderNumber , EsOrder esOrder , BigDecimal returnPrice) throws Exception {
String key = joinPayConfig.getPrivateKey();
Map<String, String> map = new HashMap<String, String>();
map.put("p0_version", "2.3"); // 接口版本号
map.put("p1_MerchantNo", joinPayConfig.getUserNo());//商户编号
map.put("p2_OrderNo", orderNumber); //商户原支付订单号
map.put("p3_RefundOrderNo", orderNumber);// 商户退款订单号
map.put("p4_RefundAmount", String.valueOf(returnPrice)); //退款金额
map.put("p5_RefundReason", ""); // 退款原因描述
map.put("p6_NotifyUrl", joinPayConfig.getRefundNotifyUrl()); // 异步地址
String Strmap = CreateLinkStringByGet1.createLinkStringByGet(map);
// 签名
String sign = Md5_Sign.SignByMD5(Strmap, key);
map.put("hmac", sign);
// post请求参数内容
StringBuffer param = new StringBuffer();
for (String k : map.keySet()) {
param.append("&");
param.append(k).append("=").append(map.get(k));
}
HttpResponse response = HttpRequest.post("https://trade.joinpay.com/tradeRt/refund")
.header("Content-Type", "application/x-www-form-urlencoded")
.body(param.toString())
.execute();
boolean yesorno = nosign(response.body(), key);
if (yesorno) {
System.out.println("验签成功");
JSONObject myJson = JSONObject.parseObject(response.body());
Map m = myJson;
if (m.get("rb_Code").equals("100")) {
//...
}else{
//...
}
Object rcCodeMsg = m.get("rc_CodeMsg");
return rcCodeMsg.toString();
} else {
System.out.println("验签失败");
return "退款发起失败";
}
}
//退款回调
public void refundNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
String key = joinPayConfig.getPrivateKey();
response.setContentType("text/plain;charset=utf-8");
response.setCharacterEncoding("utf-8");
try {
Map<String, String> requestParamsAsMap = getRequestParamsAsMap(request);
String r2_RefundOrderNo = requestParamsAsMap.get("r3_RefundOrderNo");
Map<String, String> map = new HashMap<String, String>();
map.put("p0_Version", "2.3"); // 接口版本号
map.put("p1_MerchantNo", joinPayConfig.getUserNo());//商户编号
map.put("p2_RefundOrderNo", r2_RefundOrderNo);// 商户退款订单号
String Strmap = CreateLinkStringByGet1.createLinkStringByGet(map);
// 签名
String sign = "";
sign = Md5_Sign.SignByMD5(Strmap, key);
map.put("hmac", sign);/** 签名数据 */
System.out.println("发送:" + JSON.toJSONString(map).toString());
// post请求参数内容
StringBuffer param = new StringBuffer();
for (String k : map.keySet()) {
param.append("&");
param.append(k).append("=").append(map.get(k));
}
HttpResponse resp = HttpRequest.post("https://trade.joinpay.com/tradeRt/queryRefund")
.header("Content-Type", "application/x-www-form-urlencoded")
.body(param.toString())
.execute();
System.out.println("接收返回参数:" + resp.body());
boolean yesorno = nosign(resp.body(), key);
if (yesorno) {
System.out.println("退款查询验签成功");
JSONObject resData = JSONObject.parseObject(resp.body());
Map mp = resData;
if(mp.get("ra_Status").equals("100")){
response.setStatus(200);
response.getWriter().write("success");
response.getWriter().flush();
response.getWriter().close();
}
} else {
System.out.println("退款查询验签失败");
}
} catch (Exception e) {
log.error("退款回调处理失败:" + e.getMessage());
response.setStatus(500);
response.getWriter().flush();
response.getWriter().close();
}
}
代付&代付回调
//代付接口
public void singlePay(EsDistributionWithdrawDepositRecord record) throws Exception {
String key = joinPayConfig.getPrivateKey();
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String nowStr = now.format(formatter);
Map<String, Object> map = new HashMap<>();
map.put("userNo", joinPayConfig.getUserNo());// 商户编号
map.put("productCode", joinPayConfig.getProductCode());//产品类型
map.put("requestTime", nowStr); // 交易请求时间
map.put("merchantOrderNo", record.getWithdrawDepositRecordNumber());//商户订单号
map.put("receiverAccountNoEnc", record.getBankCardNumber()); // 收款账户号
map.put("receiverNameEnc", record.getBankCardHolder()); // 收款人
map.put("receiverAccountType", record.getCarType());//账户类型
if(record.getRoutingNumber() == null){
record.setRoutingNumber("");
}
map.put("receiverBankChannelNo", record.getRoutingNumber()); // 收款账户联行号
map.put("paidAmount", record.getWithdrawDepositAmount()); //交易金额
map.put("currency", "201");//币种,201人民币
map.put("isChecked", joinPayConfig.getIsChecked());//是否复核
map.put("paidDesc", "其他");//代付说明
map.put("paidUse", joinPayConfig.getPaidUse());//代付用途
map.put("callbackUrl", joinPayConfig.getPaidNotifyUrl());//商户通知地址
map.put("firstProductCode", "");//优先使用产品
String reqSign = getRequestSign(map);
// 签名
String hmac = Md5_Sign.SignByMD5(reqSign, key);
map.put("hmac", hmac);
// post请求参数内容
String reqBodyJson = JSON.toJSONString(map);
System.out.println("reqBodyJson:" + reqBodyJson);
String httpResponseJson = HttpClientUtil
.sendHttpPost("https://www.joinpay.com/payment/pay/singlePay",reqBodyJson);
doResponseInfo(httpResponseJson, key , record);
}
//代付回调
public void singlePayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
String key = joinPayConfig.getPrivateKey();
response.setContentType("application/json;charset=utf-8");
response.setCharacterEncoding("utf-8");
try {
String jsonBody = getRequestBody(request);
ObjectMapper mapper = new ObjectMapper();
singPayDTO singPayDTO = mapper.readValue(jsonBody, singPayDTO.class);
String merchantOrderNo = singPayDTO.getMerchantOrderNo();
Map<String, Object> map = new HashMap<>();
map.put("userNo", joinPayConfig.getUserNo());// 商户编号
map.put("merchantOrderNo", merchantOrderNo);//商户订单号
String reqSignSend = singlePaySearchGetRequestSign(map);
// 签名
String hmac = Md5_Sign.SignByMD5(reqSignSend, key);
map.put("hmac", hmac);
// Map转json字符串
String reqBodyJson = JSON.toJSONString(map);
String httpResponseJson = HttpClientUtil
.sendHttpPost("https://www.joinpay.com/payment/pay/singlePayQuery",reqBodyJson);
// 响应信息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 respSign = singlePaySearchGetResponseSign(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) {
System.out.println("代查询验签成功");
System.out.println("代付查询返回参数:" + dataMap);
String statusCode = dataMap.get("status").toString();
response.getWriter().print("{\"statusCode\": \"2001\", \"message\": \"成功\"}");
response.setStatus(200);
response.getWriter().flush();
response.getWriter().close();
} else {
System.out.println("代付查询验签失败");
}
} catch (Exception e) {
log.error("代付回调处理失败:" + e.getMessage());
response.setStatus(500);
response.getWriter().flush();
response.getWriter().close();
}
}

被折叠的 条评论
为什么被折叠?



