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

上一篇已经获取到了用户的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()
   +"&notify_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。后面支付需要它。

(0)

相关推荐

  • 微信公众平台开发接口PHP SDK完整版

    代码如下: 更新日志: 2013-01-01 版本1.02014-03-15 增加图片.视频.语音的内容回复2014-04-09 增加菜单链接事件2014-04-10 修改文本回复的判定方法 复制代码 代码如下: <?php/*    方倍工作室    CopyRight 2014 All Rights Reserved*/ define("TOKEN", "weixin"); $wechatObj = new wechatCallbackapiTest();

  • 微信公众平台开发-微信服务器IP接口实例(含源码)

    学习了access_token的获取及应用后,正式的使用access_token调用下其他微信公众平台的接口,加深认识与使用方法. 一.获取微信服务器IP地址实例 (一)接口介绍 如果公众号基于安全等考虑,需要获知微信服务器的IP地址列表,以便进行相关限制,可以通过该接口获得微信服务器IP地址列表或者IP网段信息. (二)实例调用 接口说明 http请求方式:GET 接口调用地址: https://api.weixin.qq.com/cgi-bin/getcallbackip?access_to

  • ASP 微信公共平台接口实现代码

    复制代码 代码如下: <%@Language="VBScript" CodePage="65001"%><%'**********************************************'注意事项'ASP文件需要以UTF-8的格式保存,否则乱码.'以下两行代码是为了通过微信接口验证的.'response.write request("echostr")'response.end'*****************

  • java微信开发API第一步 服务器接入

    微信开发API如何接入服务器,下面就为大家进行介绍 一.说明 * 本示例根据微信开发文档:http://mp.weixin.qq.com/wiki/home/index.html最新版(4/3/2016 5:34:36 PM )进行开发演示. * 编辑平台:myeclipse10.7+win32+jdk1.7+tomcat7.0  * 服务器:阿里云 windows server 2008 64bits * 平台要求:servlet使用注解方式,平台要求:j2ee6.0+.jdk6.0+.tom

  • PHP对接微信公众平台消息接口开发流程教程

    一.写好接口程序 在你的服务器上上传好一个接口程序文件,如http://www.yourdomain.com/weixin.php  内容如下: 复制代码 代码如下: <?phpdefine("TOKEN", "weixin");//自己定义的token 就是个通信的私钥$wechatObj = new wechatCallbackapiTest();$wechatObj->valid();//$wechatObj->responseMsg();c

  • C#微信开发(服务器配置)

    小编对微信开发颇感兴趣,查阅了网上相关文章进行整理,方便大家一起学习. 1.注册帐号--填写服务器配置 在https://mp.weixin.qq.com/ 微信公众平台上注册帐号: 服务号是公司申请的微信公共账号,订阅号是个人申请的,个人权限比较少: 登录微信公众平台官网后,在公众平台后台管理页面 - 开发者中心页,点击"修改配置"按钮,填写服务器地址(URL).Token和EncodingAESKey,其中URL是开发者用来接收微信消息和事件 的接口URL.Token可由开发者可以

  • c#使用微信接口开发微信门户应用

    微信应用如火如荼,很多公司都希望搭上信息快车,这个是一个商机,也是一个技术的方向,因此,有空研究下.学习下微信的相关开发,也就成为日常计划的重要事情之一了.本系列文章希望从一个循序渐进的角度上,全面介绍微信的相关开发过程和相关经验总结,希望给大家了解一下相关的开发历程.本随笔主要针对微信开发过程的前期准备和一些初始的工作的介绍. 在写下本文的之前一周时间里,我主要就是参考一些介绍文章以及微信公众平台的相关接口说明,并结合C#的代码开发,整理了自己公司的门户界面,实现了微信工作号的初步用户交互和信

  • 微信JS接口汇总及使用详解

    基本说明 使用说明 1.引入JS文件 在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.0.0.js 备注:支持使用 AMD/CMD 标准模块加载方法加载 2.注入配置config接口 所有需要使用JSSDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用). 复制代码 代码如下: wx.config({  debug:

  • 微信API接口大全

    微信入口绑定,微信事件处理,微信API全部操作包含在这些文件中. 微信支付.微信红包.微信卡券.微信小店. 1. [代码]index.php <?php include_once 'lib.inc.php'; $wcObj = new WeChat("YOUKUIYUAN"); $wcObj->wcValid(); 2. [代码]微信入口类 <?php /** * Description of wechat * * @author Administrator */ c

  • .net实现微信公众账号接口开发实例代码

    说起微信公众帐号,大家都不会陌生,使用这个平台能给网站或系统增加一个新亮点,直接进入正题吧,在使用之前一定要仔细阅读官方API文档.API文档地址:http://mp.weixin.qq.com/wiki/index.php 使用.net实现的方法://微信接口地址 页面代码: 复制代码 代码如下: weixin _wx = new weixin();  string postStr = "";  if (Request.HttpMethod.ToLower() == "po

随机推荐