微信公众号支付(二)实现统一下单接口

广告:宝塔服务器面板,一键全能部署及管理,送你10850元礼包,点我领取~~~

微信公众号支付(二)实现统一下单接口

上一篇已经获取到了用户的OpenId

这篇主要是调用微信公众支付的统一下单API

API地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

看文档,主要流程就是把20个左右的参数封装为XML格式发送到微信给的接口地址,然后就可以获取到返回的内容了,如果成功里面就有支付所需要的预支付ID

请求参数就不解释了。

其中,随机字符串:我用的是UUID去中划线

public static String create_nonce_str() {return UUID.randomUUID().toString().replace("-","");}
登录后复制

商户订单号:每个订单号只能使用一次,所以用的是系统的订单号加的时间戳。

总金额:不能为

通知地址:微信支付成功或失败回调给系统的地址

签名:

import java.io.Serializable; public class PayInfo implements Serializable{ private static final long serialVersionUID = L; private String appid; private String mch_id; private String device_info; private String nonce_str; private String sign; private String body; private String attach; private String out_trade_no; private int total_fee; private String spbill_create_ip; private String notify_url; private String trade_type; private String openid; //下面是get,set方法 }   /** * 创建统一下单的xml的java对象 * @param bizOrder 系统中的业务单号 * @param ip 用户的ip地址 * @param openId 用户的openId * @return */ public PayInfo createPayInfo(BizOrder bizOrder,String ip,String openId) {  PayInfo payInfo = new PayInfo();  payInfo.setAppid(Constants.appid);  payInfo.setDevice_info("WEB");  payInfo.setMch_id(Constants.mch_id);  payInfo.setNonce_str(CommonUtil.create_nonce_str().replace("-", ""));  payInfo.setBody("这里是某某白米饭的body");  payInfo.setAttach(bizOrder.getId());  payInfo.setOut_trade_no(bizOrder.getOrderCode().concat("A").concat(DateFormatUtils.format(new Date(), "MMddHHmmss")));  payInfo.setTotal_fee((int)bizOrder.getFeeAmount());  payInfo.setSpbill_create_ip(ip);  payInfo.setNotify_url(Constants.notify_url);  payInfo.setTrade_type("JSAPI");  payInfo.setOpenid(openId);  return payInfo; }
登录后复制

获取签名:

/** * 获取签名 * @param payInfo * @return * @throws Exception */ public String getSign(PayInfo payInfo) throws Exception {  String signTemp = "appid="+payInfo.getAppid()   +"&attach="+payInfo.getAttach()   +"&body="+payInfo.getBody()   +"&device_info="+payInfo.getDevice_info()   +"&mch_id="+payInfo.getMch_id()   +"&nonce_str="+payInfo.getNonce_str()   +"¬ify_url="+payInfo.getNotify_url()   +"&openid="+payInfo.getOpenid()   +"&out_trade_no="+payInfo.getOut_trade_no()   +"&spbill_create_ip="+payInfo.getSpbill_create_ip()   +"&total_fee="+payInfo.getTotal_fee()   +"&trade_type="+payInfo.getTrade_type()   +"&key="+Constants.key; //这个key注意 MessageDigest md = MessageDigest.getInstance("MD"); md.reset(); md.update(signTemp.getBytes("UTF-")); String sign = CommonUtil.byteToStr(md.digest()).toUpperCase(); return sign; }
登录后复制

注意:上面的Constants.key取值在商户号API安全的API密钥中。

一些工具方法:获取ip地址,将字节数组转换为十六进制字符串,将字节转换为十六进制字符串

/*** 将字节数组转换为十六进制字符串** @param byteArray* @return*/public static String byteToStr(byte[] byteArray) { String strDigest = ""; for (int i = ; i < byteArray.length; i++) { strDigest += byteToHexStr(byteArray[i]); } return strDigest;}/*** 将字节转换为十六进制字符串** @param btyes* @return*/public static String byteToHexStr(byte bytes) { char[] Digit = { '', '', '', '', '', '', '', '', '', '', 'A', 'B', 'C', 'D', 'E', 'F' }; char[] tempArr = new char[]; tempArr[] = Digit[(bytes >>> ) & XF]; tempArr[] = Digit[bytes & XF]; String s = new String(tempArr); return s;}/*** 获取ip地址* @param request* @return*/public static String getIpAddr(HttpServletRequest request) { InetAddress addr = null; try { addr = InetAddress.getLocalHost(); } catch (UnknownHostException e) { return request.getRemoteAddr(); } byte[] ipAddr = addr.getAddress(); String ipAddrStr = ""; for (int i = ; i < ipAddr.length; i++) { if (i > ) {  ipAddrStr += "."; } ipAddrStr += ipAddr[i] & xFF; } return ipAddrStr;}
登录后复制

这样就获取了签名,把签名与PayInfo中的其他数据转成XML格式,当做参数传递给统一下单地址。

PayInfo pi = pu.createPayInfo(bo,"...","");String sign = pu.getSign(pi);pi.setSign(sign);
登录后复制

对象转XML

/*** 扩展xstream使其支持CDATA*/private static XStream xstream = new XStream(new XppDriver() { public HierarchicalStreamWriter createWriter(Writer out) { return new PrettyPrintWriter(out) {  //增加CDATA标记  boolean cdata = true;  @SuppressWarnings("rawtypes")  public void startNode(String name, Class clazz) {  super.startNode(name, clazz);  }  protected void writeText(QuickWriter writer, String text) {  if (cdata) {   writer.write("<![CDATA[");   writer.write(text);   writer.write("]]>");  } else {   writer.write(text);  }  } }; }});public static String payInfoToXML(PayInfo pi) { xstream.alias("xml", pi.getClass()); return xstream.toXML(pi);}
登录后复制

xml转Map

@SuppressWarnings("unchecked")public static Map<String, String> parseXml(String xml) throws Exception { Map<String, String> map = new HashMap<String, String>(); Document document = DocumentHelper.parseText(xml); Element root = document.getRootElement(); List<Element> elementList = root.elements(); for (Element e : elementList) map.put(e.getName(), e.getText()); return map;}
登录后复制

下面就是调用统一下单的URL了

log.info(MessageUtil.payInfoToXML(pi).replace("__", "_"));   Map<String, String> map = CommonUtil.httpsRequestToXML("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST", MessageUtil.payInfoToXML(pi).replace("__", "_").replace("<![CDATA[", "").replace("]]>", "")); log.info(map);  public static Map<String, String> httpsRequestToXML(String requestUrl, String requestMethod, String outputStr) {  Map<String, String> result = new HashMap<>();  try {  StringBuffer buffer = httpsRequest(requestUrl, requestMethod, outputStr);  result = MessageUtil.parseXml(buffer.toString());  } catch (ConnectException ce) {  log.error("连接超时:"+ce.getMessage());  } catch (Exception e) {  log.error("https请求异常:"+ece.getMessage());  }  return result; }
登录后复制

httpsRequest()这个方法在第一篇中

上面获取到的Map如果成功的话,里面就会有

String return_code = map.get("return_code"); if(StringUtils.isNotBlank(return_code) && return_code.equals("SUCCESS")){   String return_msg = map.get("return_msg"); if(StringUtils.isNotBlank(return_msg) && !return_msg.equals("OK")) {   return "统一下单错误!"; } }else{   return "统一下单错误!"; } String prepay_Id = map.get("prepay_id");
登录后复制

这个prepay_id就是预支付的ID。后面支付需要它。

更多微信公众号支付(二)实现统一下单接口相关文章请关注PHP中文网!

9543建站博客
一个专注于网站开发、微信开发的技术类纯净博客。
作者头像
admin创始人

肥猫,知名SEO博客站长,14年SEO经验。

上一篇:浅析小程序中textarea层级过高穿透问题的解决方案
下一篇:bootstrap官网的组件直接可以拿来用吗

发表评论

关闭广告
关闭广告