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

互联网 17-2-4
上一篇已经获取到了用户的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;   }

一些工具方法:获取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;   }

上面获取到的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中文网!

来源链接:
免责声明:
1.资讯内容不构成投资建议,投资者应独立决策并自行承担风险
2.本文版权归属原作所有,仅代表作者本人观点,不代表本站的观点或立场
上一篇:php获取远程图片并下载保存到本地的方法分析 下一篇:微信公众号支付(一)如何获取用户openId

相关资讯