Commit 7b2af1cc authored by 胡建龙's avatar 胡建龙

20220415 未整理接口

parent 95a9ed4a
...@@ -264,6 +264,7 @@ ...@@ -264,6 +264,7 @@
<groupId>org.bouncycastle</groupId> <groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId> <artifactId>bcprov-jdk15on</artifactId>
<version>1.65.01</version> <version>1.65.01</version>
<!-- <version>1.47</version>-->
<scope>system</scope> <scope>system</scope>
<systemPath> <systemPath>
${project.basedir}/src/main/webapp/WEB-INF/lib/bcprov-jdk15on-1.65.01.jar ${project.basedir}/src/main/webapp/WEB-INF/lib/bcprov-jdk15on-1.65.01.jar
......
...@@ -22,6 +22,7 @@ import org.springframework.web.bind.annotation.RequestMapping; ...@@ -22,6 +22,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/* /*
* 〈〉 * 〈〉
...@@ -53,4 +54,40 @@ public class HclcCmbPolyController extends BaseController { ...@@ -53,4 +54,40 @@ public class HclcCmbPolyController extends BaseController {
return jsonResult; return jsonResult;
} }
/**
* 主动请求订单状态结果
* @param request
* @param params
* @return
*/
@ResponseBody
@RequestMapping("/cmb/poly/query/order/status")
public JSONObject queryOrderStatus(HttpServletRequest request,
@RequestBody(required = true) JSONObject params) {
JSONObject jsonResult = new JSONObject();
IRequest iRequest = createRequestContext(request);
jsonResult = hclcCmbPolyService.queryOrderStatus(iRequest, params);
return jsonResult;
}
/**
* 暴露出去的回调地址,被动获取订单状态结果
* @param request
* @param params
* @return
*/
@ResponseBody
@RequestMapping("/cmb/poly/order/notify")
public Map<String, String> orderStatusNotify(HttpServletRequest request,
@RequestBody(required = true) JSONObject params) {
IRequest iRequest = createRequestContext(request);
return hclcCmbPolyService.orderNotify(iRequest, params);
}
//订单关闭 4.7.1
} }
\ No newline at end of file
...@@ -3,9 +3,14 @@ package com.cmb.service; ...@@ -3,9 +3,14 @@ package com.cmb.service;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.hand.hap.core.IRequest; import com.hand.hap.core.IRequest;
import java.util.Map;
public interface HclcCmbPolyService { public interface HclcCmbPolyService {
JSONObject getQrcode(IRequest iRequest, JSONObject params); JSONObject getQrcode(IRequest iRequest, JSONObject params);
JSONObject queryOrderStatus(IRequest iRequest, JSONObject params);
Map orderNotify(IRequest iRequest, JSONObject params);
} }
...@@ -2,10 +2,7 @@ package com.cmb.service.impl; ...@@ -2,10 +2,7 @@ package com.cmb.service.impl;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.cmb.service.HclcCmbPolyService; import com.cmb.service.HclcCmbPolyService;
import com.cmb.util.MD5Utils; import com.cmb.util.*;
import com.cmb.util.SM2Util;
import com.cmb.util.SignatureUtil;
import com.cmb.util.Utils;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.hand.hap.core.IRequest; import com.hand.hap.core.IRequest;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
...@@ -14,10 +11,14 @@ import org.springframework.stereotype.Service; ...@@ -14,10 +11,14 @@ import org.springframework.stereotype.Service;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.stream.Collectors;
@Service @Service
public class HclcCmbPolyServiceImpl implements HclcCmbPolyService { public class HclcCmbPolyServiceImpl implements HclcCmbPolyService {
private static final String url = "https://api.cmburl.cn:8065/polypay/v1.0/mchorders/qrcodeapply"; //UAT private static final String url = "https://api.cmburl.cn:8065/polypay/v1.0/mchorders/qrcodeapply"; //UAT
//需要补充域名加端口==================================================================
private static final String notifyUrl = "/cmb/poly/order/notify";
//uat环境商户国密私钥 //uat环境商户国密私钥
public static final String privateKey = "D5F2AFA24E6BA9071B54A8C9AD735F9A1DE9C4657FA386C09B592694BC118B38"; public static final String privateKey = "D5F2AFA24E6BA9071B54A8C9AD735F9A1DE9C4657FA386C09B592694BC118B38";
//uat环境招行国密公钥 //uat环境招行国密公钥
...@@ -39,6 +40,33 @@ public class HclcCmbPolyServiceImpl implements HclcCmbPolyService { ...@@ -39,6 +40,33 @@ public class HclcCmbPolyServiceImpl implements HclcCmbPolyService {
@Override @Override
public JSONObject getQrcode(IRequest iRequest, JSONObject params) { public JSONObject getQrcode(IRequest iRequest, JSONObject params) {
/*
版本号 version String(5) 是 固定为0.0.1
编码方式 encoding String(20) 是 固定为UTF-8
签名 sign String(1024) 是
签名方法 signMethod String(2) 是 02:SM2
商户号 merId String(32) 是 商户在招行完成商户进件后分配的招行商户号
商户订单号 orderId String(32) 是 商户端生成,要求此订单号在整个商户下唯一
收银员 userId String(32) 是 招行系统生成的收银员,每个收银员均会对应到一个门店。若商户无门店、收银员概念则上送默认的虚拟收银员即可。
终端号 termId String(8) 否 原则是可以通过交易上送的终端编号准确定位商户每一个门店内每一台收银设备,建议按“门店编号+收银机编号”或“设备编号”组成8位终端编号在交易中上送
支付有效时间 payValidTime String(10) 否 二维码的有效时长,单位为秒,若商户上送,则以商户上送值为准,否则使用默认有效时长1200秒
交易通知地址 notifyUrl String(256) 是 支付结果将送到本通知
交易金额 txnAmt String(13) 是 单位为分
交易币种 currencyCode String(3) 否 默认156,目前只支持人民币(156)
商品描述 body String(128) 否 用于展示支付宝账单详情中的“商品说明”和微信账单详情中的“商品”字段,若不上送则默认显示商户简称。
商户保留域 mchReserved String(128) 否 用于传输商户自定义数据,在支付结果查询和支付结果通知时原样返回(不上送则不返回此字段)
交易场景 tradeScene String(13) 是 OFFLINE:线下
ONLINE:线上
INSURANCE:保险
CHARITY:公益
PAYMENT: 缴费
SCHOOL:校园
商户门店号 mchStoreId String(32) 否 商户门店号
终端信息 terminalInfo String(6000) 否 商户侧受理终端信息,字段说明详见终端信息terminalInfo。
*/
JSONObject result = new JSONObject(); JSONObject result = new JSONObject();
Map<String, String> requestPublicParams = JSONObject.parseObject(params.toJSONString(),Map.class); Map<String, String> requestPublicParams = JSONObject.parseObject(params.toJSONString(),Map.class);
...@@ -109,6 +137,8 @@ public class HclcCmbPolyServiceImpl implements HclcCmbPolyService { ...@@ -109,6 +137,8 @@ public class HclcCmbPolyServiceImpl implements HclcCmbPolyService {
} }
} }
private String signMethod(Map paramsMap){ private String signMethod(Map paramsMap){
Map<String, String> requestPublicParams = new TreeMap<>(); Map<String, String> requestPublicParams = new TreeMap<>();
String requestStr = null; String requestStr = null;
...@@ -117,6 +147,7 @@ public class HclcCmbPolyServiceImpl implements HclcCmbPolyService { ...@@ -117,6 +147,7 @@ public class HclcCmbPolyServiceImpl implements HclcCmbPolyService {
requestPublicParams.put("version", version); //版本号,固定为0.0.1(必传字段) requestPublicParams.put("version", version); //版本号,固定为0.0.1(必传字段)
requestPublicParams.put("encoding", encoding); //编码方式,固定为UTF-8(必传) requestPublicParams.put("encoding", encoding); //编码方式,固定为UTF-8(必传)
requestPublicParams.put("signMethod", signMethod); //签名方法,固定为02,表示签名方式为国密(必传) requestPublicParams.put("signMethod", signMethod); //签名方法,固定为02,表示签名方式为国密(必传)
requestPublicParams.put("notifyUrl", notifyUrl);
// //业务要素 // //业务要素
// Map<String, String> requestTransactionParams = new HashMap<>(); // Map<String, String> requestTransactionParams = new HashMap<>();
// requestTransactionParams.put("body", "聚合支付测试"); //商户号(必传) // requestTransactionParams.put("body", "聚合支付测试"); //商户号(必传)
...@@ -173,4 +204,176 @@ public class HclcCmbPolyServiceImpl implements HclcCmbPolyService { ...@@ -173,4 +204,176 @@ public class HclcCmbPolyServiceImpl implements HclcCmbPolyService {
return false; return false;
} }
} }
@Override
public JSONObject queryOrderStatus(IRequest iRequest, JSONObject params) {
JSONObject result = new JSONObject();
final String url = "https://api.cmburl.cn:8065/polypay/v1.0/mchorders/orderquery" ;
//初始化请求报文
//实体类为商户传过来的一些参数,会封装作为biz_content部分
Pojo pojo = new Pojo();
String requestString = GenerateUtil.initRequestParam(pojo);
try {
ObjectMapper objectMapper = new ObjectMapper();
Map<String,String> requestMap = objectMapper.readValue(requestString,Map.class);
long currentTimeMills = System.currentTimeMillis() / 1000;
//对请求报文进行加密
Map<String,String> apiEncMap = new HashMap<>();
apiEncMap.put("appid",appId);
apiEncMap.put("secret",appSecret);
apiEncMap.put("sign",requestMap.get("sign"));
apiEncMap.put("timestamp",""+currentTimeMills);
//MD5加密
String MD5Content = SignatureUtil.getSignContent(apiEncMap);
String apiEncString = MD5Utils.getMD5Content(MD5Content).toLowerCase();
//组请求报文头
Map<String,String> requstHeader = new HashMap<>();
requstHeader.put("appid",appId);
requstHeader.put("timestamp",""+currentTimeMills);
requstHeader.put("apisign",apiEncString);
//发送http请求
Map<String,String> responseMap = Utils.postForEntity(url,requestString,requstHeader);
//处理响应报文
GenerateUtil.handleResponse(responseMap);
}catch (Exception ex) {
ex.printStackTrace();
}
return result;
}
@Override
public Map<String, String> orderNotify(IRequest iRequest, JSONObject params) {
/*
版本号 version String(5) 是 固定为0.0.1
编码方式 encoding String(20) 是 固定为UTF-8
签名 sign String(1024) 是
签名方法 signMethod String(2) 是 02:SM2
商户号 merId String(32) 是 商户在招行完成商户进件后分配的招行商户号
商户订单号 orderId String(32) 是 支付交易的商户订单号
平台订单号 cmbOrderId String(32) 是 招行生成的订单号
收银员 userId String(32) 否 支付交易的收银员信息,若有,则返回
交易金额 txnAmt String(13) 是 单位为分
优惠金额 dscAmt String(13) 是 单位为分
银联优惠信息 couponInfo String(500) 否 银联通道且有优惠活动时出现,字段说明详见2.6优惠信息字段说明
订单原始金额 orderOrigAmt String(13) 否 单位为分,请求上送orderOrigAmt则对应返回该内容
订单优惠金额 orderCouponAmt String(13) 否 单位为分,请求上送orderCouponAmt则对应返回该内容
优惠券信息 promotionDetail String 否 微信、支付宝优惠券信息,规则见2.6优惠信息字段说明
交易币种 currencyCode String(3) 是 目前只支持人民币(156)
支付方式 payType String(2) 是 目前支持:支付宝/微信/银联
ZF:支付宝
WX:微信
YL:银联
用户标识 openId String(128) 否 支付宝支付:用户在支付宝系统的唯一标识
微信支付:商户上送sub_appid时返回用户在sub_appid下的sub_openid
付款银行 payBank String(32) 否 支付宝支付:
ALIPAYACCOUNT 支付宝账户
PCREDIT 蚂蚁花呗
DEBIT_CARD 借记卡
CREDIT_CARD 信用卡
MIXED_CARD 借贷合一卡 等
微信支付:CMB_CREDIT 等
第三方订单号 thirdOrderId String(64) 否 支付宝、微信侧的订单号
支付宝账户 buyerLogonId String(64) 否 支付宝支付的交易返回,如:koh***@sandbox.com
订单发送时间 txnTime String(14) 是 支付订单生成的时间,格式为yyyyMMddHHmmss
订单完成日期 endDate String(8) 否 第三方系统返回的交易完成日期,此日期仅在交易成功是返回,不保证是实际清算日期,格式为yyyyMMdd
订单完成时间 endTime String(6) 否 第三方系统返回的交易完成时间,此时间仅在交易成功是返回,格式为HHmmss
支付宝和微信通道的成功交易返回此字段
银联通道的交易无论成功与否,均不返回此字段
商户保留域 mchReserved String(128) 否 若原交易有上送此字段,则返回此字段
*/
JSONObject result = new JSONObject();
System.out.println(params);
String requestBodyString = params.toJSONString();
Map<String, String> respData = new HashMap<>();
/*
版本号 version String(5) 是 固定为0.0.1
编码方式 encoding String(20) 是 固定为UTF-8
签名 sign String(1024) 是
签名方法 signMethod String(2) 是 02:SM2
返回码 returnCode String(7) 是 SUCCESS/FAIL,SUCCESS表示商户接收通知成功并校验成功
以下字段仅在returnCode为SUCCESS时返回
响应码 respCode String(10) 是 商户返回的业务错误码,成功为SUCCESS,失败为FAIL
应答信息 respMsg String(256) 否 请求处理失败的详细描述信息
*/
//设置响应数据
respData.put("version", "0.0.1");//版本号,固定为0.0.1(必传)
respData.put("encoding", "UTF-8");//编码方式,固定为UTF-8(必传)
respData.put("signMethod", "02");//签名方法,固定为02,国密
try {
respData.put("returnCode", "SUCCESS"); //SUCCESS表示商户接收通知成功并校验成功
//非空校验
if (requestBodyString == null || "".equals(requestBodyString.trim())) {
respData.put("returnCode", "FAIL");
return respData;
}
Map<String, String> requestBodyMap = str2Map(requestBodyString);
Map<String, String> resultMap = requestBodyMap.entrySet().stream().collect(Collectors.toMap(e -> SignatureUtil.decode(e.getKey()), e -> SignatureUtil.decode(e.getValue())));
if (resultMap == null) {
respData.put("returnCode", "FAIL");
return respData;
}
String sign = resultMap.remove("sign");
//对待加签内容进行排序拼接
String contentStr = SignatureUtil.getSignContent(resultMap);
//验证签名-使用招行公钥进行验签
boolean flag = SM2Util.sm2Check(contentStr,sign, publicKey);
if (!flag) {
//验签失败
System.out.println("验签失败");
respData.put("returnCode", "FAIL");
return respData;
}
System.out.println("验签成功");
//......(处理自身业务逻辑)
//......
//......
respData.put("respCode", "SUCCESS");//业务错误码,成功为SUCCESS,失败为FAIL
/*如果处理自身业务逻辑发生错误,返回
respData.put("respCode","FAIL");
respData.put("respMsg","error_msg");
*/
//对待加签内容进行排序拼接
String signContent = SignatureUtil.getSignContent(respData);
//加签-使用商户私钥加签
respData.put("sign", SM2Util.sm2Sign(signContent, privateKey));
System.out.println("加签成功");
return respData;
} catch (Exception e) {
e.printStackTrace();
respData.put("returnCode", "FAIL");
return respData;
}
}
private Map<String, String> str2Map(String str) {
Map<String, String> result = new HashMap<>();
String[] results = str.split("&");
if (results != null && results.length > 0) {
for (int var = 0; var < results.length; ++var) {
String pair = results[var];
String[] kv = pair.split("=", 2);
if (kv != null && kv.length == 2) {
result.put(kv[0], kv[1]);
}
}
}
return result;
}
} }
package com.cmb.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import java.util.HashMap;
import java.util.Map;
//构造请求报文工具类
public class GenerateUtil {
private static final Logger LOGGER = Logger.getLogger(GenerateUtil.class);
@Value("${cmb.version}")
private static String version;
@Value("${cmb.encoding}")
private static String encoding;
@Value("${cmb.signMethod}")
private static String signMethod;
public static final String privateKey = "D5F2AFA24E6BA9071B54A8C9AD735F9A1DE9C4657FA386C09B592694BC118B38";
public static final String publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE6Q+fktsnY9OFP+LpSR5Udbxf5zHCFO0PmOKlFNTxDIGl8jsPbbB/9ET23NV+acSz4FEkzD74sW2iiNVHRLiKHg==";
public static String initRequestParam(Pojo pojo){
//设置公共请求参数
Map<String,String> resultPublicParam = new HashMap<>();
resultPublicParam.put("version",version);
resultPublicParam.put("encoding",encoding);
resultPublicParam.put("sign_method", signMethod);
//初始化业务请求参数
try {
ObjectMapper objectMapper = new ObjectMapper();
String bizContent = objectMapper.writeValueAsString(pojo);
System.out.println(bizContent);
resultPublicParam.put("biz_content",bizContent);
//对待加签内容进行排序拼接
String signStr = SignatureUtil.getSignContent(resultPublicParam);
//加签
String sign = SM2Util.sm2Sign(signStr, privateKey);
resultPublicParam.put("sign",sign);
String requestStr = objectMapper.writeValueAsString(resultPublicParam);
LOGGER.info("加签后的报文内容:" + requestStr);
return requestStr;
}catch (Exception ex){
ex.printStackTrace();
return null;
}
}
/**
* 处理响应报文
* @param responseMap
* @return
*/
public static void handleResponse(Map<String,String> responseMap){
if( null == responseMap){
LOGGER.equals("响应的内容为空");
return ;
}
try {
ObjectMapper objectMapper = new ObjectMapper();
LOGGER.info("收到响应的内容为:" + objectMapper.writeValueAsString(responseMap));
//验签
String sign = responseMap.remove("sign");
//生成验签字符串
String signStr = SignatureUtil.getSignContent(responseMap);
boolean flag = SM2Util.sm2Check(signStr,sign, publicKey);
if( flag ){
LOGGER.info("验签成功!");
} else {
LOGGER.error("验签失败!");
}
return;
}catch (Exception ex){
LOGGER.equals("系统异常");
return;
}
}
}
package com.cmb.util;
public class Pojo {
public Pojo(){}
}
...@@ -5,10 +5,8 @@ package com.cmb.util; ...@@ -5,10 +5,8 @@ package com.cmb.util;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import java.io.ByteArrayInputStream; import java.io.*;
import java.io.IOException; import java.net.URLDecoder;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.security.KeyFactory; import java.security.KeyFactory;
import java.security.PrivateKey; import java.security.PrivateKey;
...@@ -87,6 +85,18 @@ public class SignatureUtil { ...@@ -87,6 +85,18 @@ public class SignatureUtil {
return content.toString(); return content.toString();
} }
public static String decode(String str) {
String result = null;
if (str != null) {
try {
result = URLDecoder.decode(str, "UTF-8");
} catch (UnsupportedEncodingException var4) {
throw new RuntimeException(var4);
}
}
return result;
}
public static boolean rsaCheck(String content, String sign, String publicKey, String charset) throws Exception { public static boolean rsaCheck(String content, String sign, String publicKey, String charset) throws Exception {
try { try {
PublicKey pubKey = getPublicKeyFromX509("RSA", new ByteArrayInputStream(publicKey.getBytes())); PublicKey pubKey = getPublicKeyFromX509("RSA", new ByteArrayInputStream(publicKey.getBytes()));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment