本文对接银联商务扫码支付,实现支付下单、订单查询、订单退款、退款查询和订单关闭几个功能,使用到银联商务的公众+服务窗支付接口规范,请自行百度下载。
一、接入前准备
创建maven项目,项目目录如下,各目录功能不再详细介绍,直接看接口和功能。
二、接口及代码实现
1.1接口规范
接口规范请查看下载的银联商务公众号+服务窗接口规范下单接口部分,这里不做展示。
1.2 代码实现
1.2.1 UnionPayScanController代码
@RestController
@CrossOrigin
@RequestMapping("/lay")
public class UnifiedPayScanController {
private final static Logger logger = LoggerFactory.getLogger(UnifiedPayScanController.class);
@Autowired
private UnifiedOrderServiceimpl unionpayserviceimpl;
/**
* 扫码付下单接口
* @param request
* @param response
* @param jsonreq
* @return
*/
@RequestMapping(value = "/UnifiedOrder", method = RequestMethod.POST)
public Map<String, Object> unionpayorder(HttpServletRequest request, HttpServletResponse response,
@RequestBody String jsonreq) {
Map<String,Object> reqmap = new HashMap<String,Object>(); //客户端原始请求map
Map<String,Object> datamap = new HashMap<String,Object>(); //客户端原始请求Data数据
Map<String,Object> resultmap = new HashMap<String,Object>(); //返回结果
//接收客户端请求数据并转换成map
reqmap = JsonUtils.JsonToMapObj(jsonreq);
logger.info("unifiedquery reqmap = " + reqmap);
datamap = (Map<String, Object>) reqmap.get("tradeParam"); //请求体数据
logger.info("unifiedquery datamap = " + datamap);
//---------------------step1 验证签名-----------------------------
String sign = (String) reqmap.get("sign"); //获取sign
String key = UnionPayConstants.GGMD5KEY; //国光MD5密钥
try {
if (!PayUtil.verifySign(datamap,key,sign)) {
resultmap.put("returnInfo", "签名错误");
resultmap.put("returnCode", "Bad_Sign");
return resultmap;
}
//----------------------step2 验证消息类型 tradeType:UnifiedOrder--------
if (!"UnifiedOrder".equals(reqmap.get("tradeType"))) {
resultmap.put("returnCode", "TradeType_Error");
resultmap.put("returnInfo", "消息类型不符");
return resultmap;
}
//-----------------------step3 验证传参完整性--------------------------
//验证公共参数完整性
if(!PayUtil.verifyParameter(datamap)) {
resultmap.put("returnCode", "Common_Value_Error");
resultmap.put("returnInfo", "缺少必要公共参数");
return resultmap;
}
//验证接口参数完整性
if(datamap.get("totalAmount").equals("") || datamap.get("msgType").equals("")
|| datamap.get("notifyUrl").equals("") || datamap.get("returnUrl").equals("") ||datamap.get("merOrderId").equals("") ) {
resultmap.put("returnCode", "Value_Error");
resultmap.put("returnInfo", "缺少必要接口参数");
return resultmap;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
resultmap.put("returnCode", "System_Error");
resultmap.put("returnInfo", "系统异常");
return resultmap;
}
//-----------------------step4 传值并调用支付链接生成接口--------------------------------
Map<String,Object> resultdatamap = new HashMap<String,Object>();
resultdatamap.put("mid", datamap.get("mid")); //商户号
resultdatamap.put("tid", datamap.get("tid")); //终端号
resultdatamap.put("instMid", datamap.get("instMid")); //机构商户号
resultdatamap.put("msgSrc", datamap.get("msgSrc")); //消息来源
// //分转元
// String Amount = PayUtil.changeF2Y(datamap.get("totalAmount").toString());
// resultdatamap.put("totalAmount", Amount); //支付总金额
resultdatamap.put("totalAmount", datamap.get("totalAmount")); //总金额
resultdatamap.put("msgType", datamap.get("msgType")); //支付类型
resultdatamap.put("notifyUrl", datamap.get("notifyUrl")); //支付结果通知
resultdatamap.put("returnUrl", datamap.get("returnUrl")); //网页跳转地址
resultdatamap.put("merOrderId", datamap.get("merOrderId")); //C端上送商户订单号
Map<String, Object> urlmap = unionpayserviceimpl.CreateUrl(resultdatamap); //生成支付链接,返回给前端生成二维码
//-----------------------step5 返回报文,支付链接--------------------------------
resultmap.put("returnCode", "SUCCESS");
//resultmap.put("returnInfo","生成支付链接成功");
Map<String,Object> urldatamap = new HashMap<String,Object>();
urldatamap.put("url", urlmap.get("url"));
//urldatamap.put("merOrderId", urlmap.get("merOrderId"));
urldatamap.put("merOrderId", datamap.get("merOrderId"));
resultmap.put("data", urldatamap);
return resultmap;
}
1.2.2 UnionpayScanServiceimpl代码
本部分代码为银联商务支付下单接口实现类。本案例对接银联商务支付下单接口,并对接口进行封装,返回给测试网页一个URL支付链接,前端接收到url后,对其进行qrCode转为二维码,用户扫描二维码后完成支付。
包括UnifiedOrder方法和CreateUrl方法,其中UnifiedOrder方法为调起银联商务支付下单的支付链接,CreateUrl方法为返回到前端用于生成支付二维码的实现类。
/**
* 银联商务支付下单
* return map
* @throws UnsupportedEncodingException
*/
@Override
public String UnifiedOrder(Map<String,Object> map) throws UnsupportedEncodingException {
// TODO Auto-generated method stub
Map<String, Object> reqmap = new HashMap<String, Object>(); //请求银联商务map
reqmap.put("mid", map.get("mid")); //商户号
reqmap.put("tid", map.get("tid")); //终端号
reqmap.put("instMid", map.get("instMid"));
reqmap.put("msgSrc", map.get("msgSrc")); //消息来源
reqmap.put("msgId", "UnionPay_F001"); //自定义
reqmap.put("msgType", map.get("msgType")); //支付类型,前端传入
//报文请求时间
String aligetTime = PayUtil.aligetTime();
logger.info("end_time = " + aligetTime);
reqmap.put("requestTimestamp", aligetTime);
//商户订单号
//reqmap.put("msgSrcId", this.msgSrcId); //来源编号
// String orderid = GGitUtil.createOrderID();
// StringBuffer buff = new StringBuffer();
// buff.append(this.msgSrcId);
// buff.append(orderid);
reqmap.put("merOrderId", map.get("merOrderId"));
reqmap.put("originalAmount", map.get("totalAmount")); //前端传入
reqmap.put("totalAmount",map.get("totalAmount")); //订单金额
reqmap.put("notifyUrl", map.get("notifyUrl")); //支付结果通知地址
reqmap.put("returnUrl", map.get("returnUrl")); //网页跳转地址
//生成待签名字符串并进行MD5加密
String builderSignStr = "";
try {
builderSignStr = PayUtil.builderSignStr(reqmap,UnionPayConstants.MD5KEY);
//signString = PayUtil.generateSignature(reqmap, UnionPayConstants.MD5KEY);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
reqmap.put("sign", builderSignStr);
logger.info("reqmap= " + reqmap);
//拼接请求URL
StringBuffer url = new StringBuffer();
try {
url.append("https://qr-test2.chinaums.com/netpay-portal/webpay/pay.do?");
url.append("requestTimestamp=" + URLEncoder.encode((String) reqmap.get("requestTimestamp"), "UTF-8") +
"&mid=" + URLEncoder.encode((String) reqmap.get("mid"), "UTF-8") +
"&tid="+ URLEncoder.encode((String) reqmap.get("tid"), "UTF-8") +
"&instMid=" + URLEncoder.encode((String) reqmap.get("instMid"), "UTF-8") +
"&msgSrc=" + URLEncoder.encode((String) reqmap.get("msgSrc"), "UTF-8") +
"&merOrderId=" + URLEncoder.encode((String) reqmap.get("merOrderId"), "UTF-8") +
"&totalAmount=" + URLEncoder.encode((String) reqmap.get("totalAmount"), "UTF-8") +
"&msgId=" + URLEncoder.encode((String) reqmap.get("msgId"), "UTF-8") +
"&msgType=" + URLEncoder.encode((String) reqmap.get("msgType"), "UTF-8") +
"&originalAmount=" + URLEncoder.encode((String) reqmap.get("originalAmount"), "UTF-8") +
"¬ifyUrl=" + URLEncoder.encode((String) reqmap.get("notifyUrl"), "UTF-8") +
"&returnUrl=" + URLEncoder.encode((String) reqmap.get("returnUrl"), "UTF-8") +
"&sign=" + URLEncoder.encode((String) reqmap.get("sign"), "UTF-8"));
logger.info("银联商务下单url = " + url);
} catch (Exception e) {
// TODO: handle exception
return "缺少必要参数,请核实后再进行下单";
}
return url.toString();
}
/**
* 生成支付链接+商户号
*/
@Override
public Map<String, Object> CreateUrl(Map<String, Object> reqmap) {
// TODO Auto-generated method stub
//生成商户订单号
//reqmap.put("msgSrcId", this.msgSrcId); //来源编号
// String orderid = GGitUtil.createOrderID();
// StringBuffer buff = new StringBuffer();
// buff.append(this.msgSrcId);
// buff.append(orderid);
// String merOrderId = buff.toString();
//拼接请求URL
String mid = (String) reqmap.get("mid");
String tid = (String) reqmap.get("tid");
String instMid = (String) reqmap.get("instMid");
String msgSrc = (String) reqmap.get("msgSrc");
String totalAmount = (String) reqmap.get("totalAmount");
String msgType = (String) reqmap.get("msgType");
String notifyUrl = (String) reqmap.get("notifyUrl");
String returnUrl = (String) reqmap.get("returnUrl");
String merOrderId = (String) reqmap.get("merOrderId");
StringBuffer url = new StringBuffer();
url.append("http://www.ggzzrj.cn:8081/unionpay/lay/unifiedpay?");
url.append("mid=" + mid + "&tid=" + tid + "&instMid=" + instMid + "&msgSrc=" + msgSrc
+ "&totalAmount=" + totalAmount + "&msgType=" + msgType + "¬ifyUrl=" + notifyUrl +"&returnUrl=" + returnUrl + "&merOrderId=" + merOrderId);
Map<String,Object> respmap = new HashMap<String,Object>();
respmap.put("merOrderId", merOrderId);
respmap.put("url", url.toString());
return respmap;
}
1.3 支付结果截图
在下单接口中,使用测试网页进行测试,用户扫描测试网页生成的支付二维码,然后调起支付页面,用户支付完成时,点击“完成”按钮,跳转到程序中指定的returnurl地址中,支付结果通知到notifyurl地址中,测试网页截图如图示。
支付页面