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

上一篇已经获取到了用户的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("

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 parseXml(String xml) throws Exception {

Map map = new HashMap();

Document document = DocumentHelper.parseText(xml);

Element root = document.getRootElement();

List elementList = root.elements();

for (Element e : elementList)

map.put(e.getName(), e.getText());

return map;

}

下面就是调用统一下单的URL了log.info(MessageUtil.payInfoToXML(pi).replace("__", "_"));

Map map = CommonUtil.httpsRequestToXML("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST", MessageUtil.payInfoToXML(pi).replace("__", "_").replace("", ""));

log.info(map);

public static Map httpsRequestToXML(String requestUrl, String requestMethod, String outputStr) {

Map 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中文网!

本文原创发布php中文网,转载请注明出处,感谢您的尊重!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值