微信公众号支付(二):统一下单

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體:   |    |    |  超大  

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

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

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

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

请求参数就不解释了。

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

1publicstaticString create_nonce_str() {2returnUUID.randomUUID().toString().replace("-","");3}

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

总金额:不能为0

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

签名:

1importjava.io.Serializable;23publicclassPayInfoimplementsSerializable{45PRivatestaticfinallongserialVersionUID = 5637164279924222380L;6privateString appid;7privateString mch_id;8privateString device_info;9privateString nonce_str;10privateString sign;11privateString body;12privateString attach;13privateString out_trade_no;14privateinttotal_fee;15privateString spbill_create_ip;16privateString notify_url;17privateString trade_type;18privateString openid;1920//下面是get,set方法21}

1/**2* 创建统一下单的xml的java对象3*@parambizOrder 系统中的业务单号4*@paramip 用户的ip地址5*@paramopenId 用户的openId6*@return7*/8publicPayInfo createPayInfo(BizOrder bizOrder,String ip,String openId) {9PayInfo payInfo =newPayInfo();10payInfo.setAppid(Constants.appid);11payInfo.setDevice_info("WEB");12payInfo.setMch_id(Constants.mch_id);13payInfo.setNonce_str(CommonUtil.create_nonce_str().replace("-", ""));14payInfo.setBody("这里是某某白米饭的body");15payInfo.setAttach(bizOrder.getId());16payInfo.setOut_trade_no(bizOrder.getOrderCode().concat("A").concat(DateFormatUtils.format(newDate(), "MMddHHmmss")));17payInfo.setTotal_fee((int)bizOrder.getFeeAmount());18payInfo.setSpbill_create_ip(ip);19payInfo.setNotify_url(Constants.notify_url);20payInfo.setTrade_type("JSAPI");21payInfo.setOpenid(openId);22returnpayInfo;23}

获取签名:

1/**2* 获取签名3*@parampayInfo4*@return5*@throwsException6*/7publicString getSign(PayInfo payInfo)throwsException {8String signTemp = "appid="+payInfo.getAppid()9+"&attach="+payInfo.getAttach()10+"&body="+payInfo.getBody()11+"&device_info="+payInfo.getDevice_info()12+"&mch_id="+payInfo.getMch_id()13+"&nonce_str="+payInfo.getNonce_str()14+"&notify_url="+payInfo.getNotify_url()15+"&openid="+payInfo.getOpenid()16+"&out_trade_no="+payInfo.getOut_trade_no()17+"&spbill_create_ip="+payInfo.getSpbill_create_ip()18+"&total_fee="+payInfo.getTotal_fee()19+"&trade_type="+payInfo.getTrade_type()20+"&key="+Constants.key;//这个key注意2122MessageDigestmd5= MessageDigest.getInstance("MD5");23md5.reset();24md5.update(signTemp.getBytes("UTF-8"));25String sign =CommonUtil.byteToStr(md5.digest()).toUpperCase();26returnsign;27}

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

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

1/**2* 将字节数组转换为十六进制字符串3*4*@parambyteArray5*@return6*/7publicstaticString byteToStr(byte[] byteArray) {8String strDigest = "";9for(inti = 0; i < byteArray.length; i++) {10strDigest +=byteToHexStr(byteArray[i]);11}12returnstrDigest;13}1415/**16* 将字节转换为十六进制字符串17*18*@parambtyes19*@return20*/21publicstaticString byteToHexStr(bytebytes) {22char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};23char[] tempArr =newchar[2];24tempArr[0] = Digit[(bytes >>> 4) & 0X0F];25tempArr[1] = Digit[bytes & 0X0F];2627String s =newString(tempArr);28returns;29}3031/**32* 获取ip地址33*@paramrequest34*@return35*/36publicstaticString getIpAddr(HttpServletRequest request) {37InetAddress addr =null;38try{39addr =InetAddress.getLocalHost();40}catch(UnknownHostException e) {41returnrequest.getRemoteAddr();42}43byte[] ipAddr =addr.getAddress();44String ipAddrStr = "";45for(inti = 0; i < ipAddr.length; i++) {46if(i > 0) {47ipAddrStr += ".";48}49ipAddrStr += ipAddr[i] & 0xFF;50}51returnipAddrStr;52}

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

1PayInfo pi = pu.createPayInfo(bo,"10.204.3.32","22");2String sign =pu.getSign(pi);3pi.setSign(sign);

对象转XML

1/**2* 扩展xstream使其支持CDATA3*/4privatestaticXStream xstream =newXStream(newXppDriver() {5publicHierarchicalStreamWriter createWriter(Writer out) {6returnnewPrettyPrintWriter(out) {7//增加CDATA标记8booleancdata =true;910@SuppressWarnings("rawtypes")11publicvoidstartNode(String name, Class clazz) {12super.startNode(name, clazz);13}1415protectedvoidwriteText(QuickWriter writer, String text) {16if(cdata) {17writer.write("<![CDATA[");18writer.write(text);19writer.write("]]>");20}else{21writer.write(text);22}23}24};25}26});2728publicstaticString payInfoToXML(PayInfo pi) {29xstream.alias("xml", pi.getClass());30returnxstream.toXML(pi);31}

xml转Map

1@SuppressWarnings("unchecked")2publicstaticMap<String, String> parseXml(String xml)throwsException {3Map<String, String> map =newHashMap<String, String>();45Document document =DocumentHelper.parseText(xml);6Element root =document.getRootElement();7List<Element> elementList =root.elements();89for(Element e : elementList)10map.put(e.getName(), e.getText());11returnmap;12}

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

1log.info(MessageUtil.payInfoToXML(pi).replace("__", "_"));2Map<String, String> map = CommonUtil.httpsRequestToXML("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST", MessageUtil.payInfoToXML(pi).replace("__", "_").replace("<![CDATA[", "").replace("]]>", ""));3log.info(map);

1publicstaticMap<String, String>httpsRequestToXML(String requestUrl, String requestMethod, String outputStr) {2Map<String, String> result =newHashMap<>();3try{4StringBuffer buffer =httpsRequest(requestUrl, requestMethod, outputStr);5result =MessageUtil.parseXml(buffer.toString());6}catch(ConnectException ce) {7log.error("连接超时:"+ce.getMessage());8}catch(Exception e) {9log.error("https请求异常:"+ece.getMessage());10}11returnresult;12}

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

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

1String return_code = map.get("return_code");2if(StringUtils.isNotBlank(return_code) && return_code.equals("SUCCESS")){3String return_msg = map.get("return_msg");4if(StringUtils.isNotBlank(return_msg) && !return_msg.equals("OK")) {5return"统一下单错误!";6}7}else{8return"统一下单错误!";9}1011String prepay_Id = map.get("prepay_id");

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

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航