java调用微信小程序统一下单接口
今天项目中对接微信支付这一块,记录一下
这是对接微信支付的开发文档地址
微信支付流程
流程分析:
我们可以看到,前端人员只用给我们一个code,我们通过code去获取用户openId,然后生成订单,再调用微信支付统一下单API,微信返回给我们一个prepay_id,我们封装起来一起返给前端即可,前端支付成功了,微信会发送通知给我们的回调地址,我们更新订单状态即可,大致流程就是这样,这篇文章主要讲的就是调用统一下单API返回prepay_id的过程
代码部分:
/**
* 支付接口
*
* @param code 前端传的只能用一次的code
* @param oderInfo 订单信息接口
* @param response 响应
* @return ResultInfo 统一结果集
*/
@RequestMapping(value = "/weChat/getPrePayId/{code}")
@ResponseBody
@ApiOperation(value = "调用微信支付统一下单接口", notes = "调用微信支付统一下单接口", httpMethod = "POST")
public ResultInfo getPrePayId(@PathVariable(value = "code") String code,
@ApiParam(name = "oderInfo", value = "订单详细信息", required = true)
@RequestBody OrderBO oderInfo,
HttpServletResponse response) {
response.addHeader("Access-Control-Allow-Origin", "*");
ResultInfo resultInfo = new ResultInfo();
//通过code获取openId
JSONObject openIdResult;
try {
openIdResult = (JSONObject) WechatUtil.getMpAccessToken(code);
if (null == openIdResult) {
resultInfo.setMsg("结果解析为空!");
resultInfo.setCode(15115);
return resultInfo;
}
} catch (JSONException e) {
resultInfo.setMsg("结果解析不正确!");
resultInfo.setCode(15114);
return resultInfo;
}
String openId = openIdResult.getString("openid");
if (StringUtil.isEmpty(openId)) {
resultInfo.setMsg("获取用户openId出错,获得空的openId!");
resultInfo.setCode(15114);
return resultInfo;
}
//生成订单
//这块我就不贴出来了,毕竟涉及到具体的业务了
SortedMap params = new TreeMap<>();
//生成32位随机数
String nonce_str = create_nonce_str().replace("-", "");
String timestamp = create_timestamp();
//商户的秘钥,在https://pay.weixin.qq.com 中获取
String apiKey = ConstantWeChat.API_KEY;
//小程序ID
params.put("appid", ConstantWeChat.APPID);
//商户号
params.put("mch_id", ConstantWeChat.MCH_ID);
//openId
params.put("openid", openId);
//商品描述
params.put("body", "APP body");
//随机字符串,要求在32位以内
params.put("nonce_str", nonce_str);
//回调地址
params.put("notify_url","http://");
//订单号
params.put("out_trade_no", oderInfo.getOrderId());
//终端ip,调用微信支付API的机器IP,即本机的ip
params.put("spbill_create_ip", "");
//支付金额,total_fee传的单位是分,不能有小数点
int totalFee = (int) (oderInfo.getPayAmount() * 100);
params.put("total_fee", String.valueOf(totalFee));
//交易类型,小程序取值如下:JSAPI
params.put("trade_type", "JSAPI");
//生成签名
String sign = WechatUtil.createSign(params, apiKey);
params.put("sign", sign);
String prepayId = null;
String wxResult;
try {
// 将post的数据转换从xml格式
String xmlObj = WechatUtil.parseXML(params);
wxResult = WechatUtil.sendPost(HttpClients.createDefault(),
"https://api.mch.weixin.qq.com/pay/unifiedorder", xmlObj);
// 解析xml获取prepayId
// 记得引入dom4j的依赖
Document doc = DocumentHelper.parseText(wxResult);
//objMap 的大小为10的时候就是调用成功了
Map objMap = WechatUtil.Dom2Map(doc);
String returnCode = (String) objMap.get("return_code");
String resultCode = (String) objMap.get("result_code");
if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) {
prepayId = (String) objMap.get("prepay_id");
}
params.put("package", "prepay_id=" + prepayId);
params.put("timestamp", timestamp);
} catch (Exception e) {
resultInfo.setMsg("解析错误!");
resultInfo.setCode(15114);
return resultInfo;
}
if (null == prepayId) {
resultInfo.setMsg("解析有误!");
resultInfo.setCode(15114);
return resultInfo;
}
SortedMap params2 = new TreeMap<>();
params2.put("appId", params.get("appid"));
params2.put("timeStamp", params.get("timestamp"));
params2.put("nonceStr", params.get("nonce_str"));
params2.put("package", "prepay_id=" + prepayId);
params2.put("signType", "MD5");
String sign2 = WechatUtil.createSign(params2, apiKey);
params2.put("paySign", sign2);
resultInfo.setData(params2);
resultInfo.setMsg("获取准备ID成功!");
return resultInfo;
}
private static String create_nonce_str() {
return UUID.randomUUID().toString();
}
private static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
用到的包
package com.miao.api.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.miao.common.utils.ResultInfo;
import com.miao.common.utils.StringUtil;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.http.impl.client.HttpClients;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;
dom4j依赖
dom4j
dom4j
1.6.1
这是WechatUtil里面的方法
/**
* 生成微信支付签名
*
* @param parameters 参数
* @param apiKey 商户秘钥
* @return String
*/
public static String createSign(SortedMap parameters,
String apiKey) {
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
Object v = entry.getValue();
if (null != v && !"".equals(v) && !"sign".equals(k)
&& !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
// 最后加密时添加商户密钥,由于key值放在最后,所以不用添加到SortMap里面去,单独处理,编码方式采用UTF-8
sb.append("key=" + apiKey);
try {
String sign = MD5.encrypt(sb.toString(), "UTF-8").toUpperCase();
return sign;
} catch (Exception e) {
}
return null;
}
public static String parseXML(SortedMap parameters) {
StringBuffer sb = new StringBuffer();
sb.append("");
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("" + parameters.get(k) + "" + k + ">\n");
}
}
sb.append("");
return sb.toString();
}
public static String sendPost(CloseableHttpClient httpclient, String url, String xmlObj) throws IOException {
String result;
HttpPost httpPost = new HttpPost(url);
// 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
StringEntity postEntity = new StringEntity(xmlObj, "UTF-8");
httpPost.addHeader("Content-Type", "text/xml");
httpPost.setEntity(postEntity);
log.info(xmlObj);
try {
CloseableHttpResponse response = httpclient.execute(httpPost);
try {
HttpEntity entity = response.getEntity();
result = EntityUtils.toString(entity, "UTF-8");
} finally {
response.close();
}
} finally {
httpclient.close();
}
return result;
}
public static Map Dom2Map(Document doc) {
Map map = new HashMap<>(16);
if (doc == null) {
return map;
}
Element root = doc.getRootElement();
for (Iterator iterator = root.elementIterator(); iterator.hasNext(); ) {
Element e = (Element) iterator.next();
List list = e.elements();
if (list.size() > 0) {
map.put(e.getName(), Dom2Map(e));
} else {
map.put(e.getName(), e.getText());
}
}
return map;
}
参数校验地址:
//检验发送参数是否规范的地址
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=20_1
提醒:
sign参数必须要在最后面生成,否则将生成错误的sign
######### 觉得还可以的话可以的话点个赞呗