3.1 获取到了openId后便可写统一下单接口,统一下单接口主要为了获取prepay_id
统一下单接口连接:https://api.mch.weixin.qq.com/pay/unifiedorder
代码如下:
请求发过去后微信会给返回参数,当return_code=SUCCESS的时候说明统一下单接口没有错误,可以取perpay_id了
必须传送的参数:
公众账号ID:appId
商户号:mch_id随机字符串:nonce_str(长度在32位以内)签名:sign商品描述:body商户订单号:out_trade_no金额:total_fee终端IP:spbill_create_ip通知类型:notify_url交易类型:trade_type(JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付)用户标识:openid(在公众号支付中,统一下单接口中的openId是必须填写的)
统一下单接口连接:https://api.mch.weixin.qq.com/pay/unifiedorder
代码如下:
// 获取http服务请求
HttpServletRequest request = Struts2Utils.getRequest();
// 微信端要求按照ASCII字码排序,所以选用SortedMap 因为MAP不会按照ASCII码排序
SortedMap<String, String> parameters = new TreeMap<String, String>();
// 公众账号ID
parameters.put("appid", );
// 商户号
parameters.put("mch_id", );
// 商品描述
parameters.put("body", );
// 随机字符串
parameters.put("nonce_str", WeiXinUtil.create_nonce_str());
// 订单号
parameters.put("out_trade_no",);
// 金额,微信金额为“分”
parameters.put("total_fee", );
// IP地址
parameters.put("spbill_create_ip", PayCcbAction.getIp(request));
// 回调地址
parameters.put("notify_url", );
// 交易类型 JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付
parameters.put("trade_type", "JSAPI");
// 用户表示openId
parameters.put("openid", );
// 以上参数加密成sign 输出查看,报签名错误,输出语句到API签名验证工具验证
String sign = Sign.sign(parameters);
parameters.put("sign", sign);
创建统一下单接口的参数,上面两个方法:WeiXinUtil.create_nonce_str()生成随机字符串。PayCcbAction.getIp() IP地址
此处工具类:
/*
* 微信JSSDK参数 随机字符串
*/
public static String create_nonce_str() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
/*
* 获取IP
*/
public static String getIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个ip值,第一个ip才是真实ip
int index = ip.indexOf(",");
if (index != -1) {
return ip.substring(0, index);
} else {
return ip;
}
}
ip = request.getHeader("X-Real-IP");
if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
return ip;
}
return request.getRemoteAddr();
}
创建完成参数以后微信要求按照ASCII字码进行排序并生成XML,并发送请求
代码如下:
// 发送请求
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder");
StringEntity entityParams = new StringEntity(XmlUtils.parseXML(parameters), "utf-8");
httpPost.setEntity(entityParams);
httpPost.setHeader("Content-Type", "text/xml;charset=ISO-8859-1");
CloseableHttpClient client = HttpClients.createDefault();
CloseableHttpResponse response = client.execute(httpPost);
发送http请求,将上面创建好的参数生成xml格式,方法XmlUtils.parseXML() 生成XML格式
代码如下:
/*
* 封装XML
*/
public static String parseXML(SortedMap<String, String> parameters) {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
Set es = parameters.entrySet();
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
String v = (String) entry.getValue();
if (null != v && !"".equals(v) && !"appkey".equals(k)) {
sb.append("<" + k + ">" + parameters.get(k) + "</" + k + ">\n");
}
}
sb.append("</xml>");
return sb.toString();
}
请求发过去后微信会给返回参数,当return_code=SUCCESS的时候说明统一下单接口没有错误,可以取perpay_id了
代码如下:
// 判断是否获取到返回信息
if (response != null && response.getEntity() != null) {
Map<String, String> resultMap = XmlUtils.toMap(EntityUtils.toByteArray(response.getEntity()), "utf-8");
// 验证微信返回是否正确
if (!SignUtils.checkParam(resultMap, WeiXinUtils.API_KEY)) {
System.out.println("=================验证签名不通过===============");
System.out.println(resultMap.get("return_code"));
System.out.println(resultMap.get("return_msg"));
} else {
// 判断返回参数是否为SUCCESS
if ("SUCCESS".equals(resultMap.get("return_code")) && "SUCCESS".equals(resultMap.get("result_code"))) {
return resultMap.get("prepay_id");
}
}
} else {
System.out.println("获取返回信息失败");
}
方法SignUtils.checkParam()验证是否参数正确,其实判断return_code是否等于SUCCESS就可以了,没必要多一步。
/**
* 验证返回参数
*/
public static boolean checkParam(Map<String, String> params, String key) {
boolean result = false;
if (params.containsKey("sign")) {
String sign = params.get("sign");
params.remove("sign");
StringBuilder buf = new StringBuilder((params.size() + 1) * 10);
SignUtils.buildPayParams(buf, params, false);
String preStr = buf.toString();
String signRecieve = MD5.sign(preStr, "&key=" + key, "utf-8");
result = sign.equalsIgnoreCase(signRecieve);
}
return result;
}