登录
注册
写文章
发现
工具
java调用微信小程序统一下单接口
_3t3lfz KEKfID
编辑文章
java调用微信小程序统一下单接口
asfx站长
2020.10.11 09:41:51
阅读
910
这是对接微信支付的开发文档地址 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_4&index=3 小程序支付的交互图如下: [![小程序支付交互图](https://pay.weixin.qq.com/wiki/doc/api/img/wxa-7-2.jpg "小程序支付交互图")](https://pay.weixin.qq.com/wiki/doc/api/img/wxa-7-2.jpg "小程序支付交互图") ##### 流程分析: 我们可以看到,前端人员只用给我们一个code,我们通过code去获取用户openId,然后生成订单,再调用微信支付统一下单API,微信返回给我们一个prepay_id,我们封装起来一起返给前端即可,前端支付成功了,微信会发送通知给我们的回调地址,我们更新订单状态即可,大致流程就是这样,这里主要讲的就是调用统一下单API返回prepay_id的过程 代码: ```java /** * 支付接口 * * @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; } // TODO 生成订单的业务代码... SortedMap<String, String> 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 = null; 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<String, Object> 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<String, String> 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); } ``` 用到的公共包: ```java import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.JSONObject; 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; ``` maven依赖: ```xml <!--dom4j--> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> ``` WechatUtil工具类: ```java /** * 生成微信支付签名 * * @param parameters 参数 * @param apiKey 商户秘钥 * @return String */ public static String createSign(SortedMap<String, String> 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<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(); } 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<String, Object> dom2Map(Document doc) { Map<String, Object> 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((Document) e)); } else { map.put(e.getName(), e.getText()); } } return map; } ``` 参数校验地址: ```java //检验发送参数是否规范的地址 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=20_1 ```
我的主页
退出