上一篇已经获取到了用户的OpenId
转载自:/888924.html
这篇主要是调用微信公众支付的统一下单API
API地址:https://pay./wiki/doc/api/jsapi.php?chapter=9_1
看文档,主要流程就是把20个左右的参数封装为xml格式发送到微信给的接口地址,然后就可以获取到返回的内容了,如果成功里面就有支付所需要的预支付ID
请求参数就不解释了。
其中,随机字符串:我用的是UUID去中划线
1 public static String create_nonce_str() {2 return UUID.randomUUID().toString().replace("-","");3 }
商户订单号:每个订单号只能使用一次,所以用的是系统的订单号加的时间戳。
总金额:不能为0
通知地址:微信支付成功或失败回调给系统的地址
签名:
1 import java.io.Serializable; 2 3 public class PayInfo implements Serializable{ 4 5 PRivate static final long serialVersionUID = 5637164279924222380L; 6 private String appid; 7 private String mch_id; 8 private String device_info; 9 private String nonce_str;10 private String sign;11 private String body;12 private String attach;13 private String out_trade_no;14 private int total_fee;15 private String spbill_create_ip;16 private String notify_url;17 private String trade_type;18 private String openid;1920 //下面是get,set方法 21 }
1 /** 2 * 创建统一下单的xml的java对象 3 * @param bizOrder 系统中的业务单号 4 * @param ip 用户的ip地址 5 * @param openId 用户的openId 6 * @return 7 */ 8 public PayInfo createPayInfo(BizOrder bizOrder,String ip,String openId) { 9PayInfo payInfo = new PayInfo();10 payInfo.setAppid(Constants.appid);11payInfo.setDevice_info("WEB");12 payInfo.setMch_id(Constants.mch_id);13payInfo.setNonce_str(CommonUtil.create_nonce_str().replace("-", ""));14payInfo.setBody("这里是某某白米饭的body");15 payInfo.setAttach(bizOrder.getId());16payInfo.setOut_trade_no(bizOrder.getOrderCode().concat("A").concat(DateFormatUtils.format(new Date(), "MMddHHmmss")));17payInfo.setTotal_fee((int)bizOrder.getFeeAmount());18 payInfo.setSpbill_create_ip(ip);19 payInfo.setNotify_url(Constants.notify_url);20payInfo.setTrade_type("JSAPI");21 payInfo.setOpenid(openId);22return payInfo;23 }
获取签名:
1 /** 2 * 获取签名 3 * @param payInfo 4 * @return 5 * @throws Exception 6 */ 7 public String getSign(PayInfo payInfo) throws Exception { 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 +"¬ify_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注意2122 MessageDigest md5 = MessageDigest.getInstance("MD5");23 md5.reset();24 md5.update(signTemp.getBytes("UTF-8"));25 String sign = CommonUtil.byteToStr(md5.digest()).toUpperCase();26 return sign;27 }
注意:上面的Constants.key取值在商户号API安全的API密钥中。
一些工具方法:获取ip地址,将字节数组转换为十六进制字符串,将字节转换为十六进制字符串
1 /** 2 * 将字节数组转换为十六进制字符串 3 *
4 * @param byteArray 5 * @return 6 */ 7 public static String byteToStr(byte[] byteArray) { 8String strDigest = ""; 9for (int i = 0; i < byteArray.length; i++) {10 strDigest += byteToHexStr(byteArray[i]);11 }12return strDigest;13 }14 15 /**16 * 将字节转换为十六进制字符串17 *
18 * @param btyes19 * @return20 */21 public static String byteToHexStr(byte bytes) {22char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };23char[] tempArr = new char[2];24tempArr[0] = Digit[(bytes >>> 4) & 0X0F];25tempArr[1] = Digit[bytes & 0X0F];26 27String s = new String(tempArr);28return s;29 }30 31 /**32 * 获取ip地址33 * @param request34 * @return35 */36 public static String getIpAddr(HttpServletRequest request) {
37InetAddress addr = null;
38try {
39 addr = InetAddress.getLocalHost();
40} catch (UnknownHostException e) {
41 return request.getRemoteAddr();
42 }
43byte[] ipAddr = addr.getAddress();
44String ipAddrStr = "";
45for (int i = 0; i < ipAddr.length; i++) {
46 if (i > 0) {
47 ipAddrStr += ".";
48}
49 ipAddrStr += ipAddr[i] & 0xFF;
50 }
51return ipAddrStr;
52 }
这样就获取了签名,把签名与PayInfo中的其他数据转成XML格式,当做参数传递给统一下单地址。
1 PayInfo pi = pu.createPayInfo(bo,"10.204.3.32","22");2 String sign = pu.getSign(pi);3 pi.setSign(sign);
对象转XML
1 /** 2 * 扩展xstream使其支持CDATA 3 */ 4 private static XStream xstream = new XStream(new XppDriver() { 5public HierarchicalStreamWriter createWriter(Writer out) { 6 return new PrettyPrintWriter(out) { 7 //增加CDATA标记 8 boolean cdata = true; 9 10 @SuppressWarnings("rawtypes")11 public void startNode(String name, Class clazz) {12 super.startNode(name, clazz);13 }14 15 protected void writeText(QuickWriter writer, String text) {16 if (cdata) {17 writer.write("<![CDATA[");18 writer.write(text);19 writer.write("]]>");20 } else {21 writer.write(text);22}23 }24};25 }26 });27 28 public static String payInfoToXML(PayInfo pi) {29xstream.alias("xml", pi.getClass());30return xstream.toXML(pi);31 }
xml转Map
1 @SuppressWarnings("unchecked") 2 public static Map<String, String> parseXml(String xml) throws Exception { 3Map<String, String> map = new HashMap<String, String>(); 4 5Document document = DocumentHelper.parseText(xml); 6Element root = document.getRootElement(); 7List<Element> elementList = root.elements(); 8 9for (Element e : elementList)10map.put(e.getName(), e.getText());11return map;12 }
下面就是调用统一下单的URL了
1 log.info(MessageUtil.payInfoToXML(pi).replace("__", "_"));2 Map<String, String> map = CommonUtil.httpsRequestToXML("https://api.mch./pay/unifiedorder", "POST", MessageUtil.payInfoToXML(pi).replace("__", "_").replace("<![CDATA[", "").replace("]]>", ""));3 log.info(map);
1 public static Map<String, String> httpsRequestToXML(String requestUrl, String requestMethod, String outputStr) { 2Map<String, String> result = new HashMap<>(); 3try { 4 StringBuffer buffer = httpsRequest(requestUrl, requestMethod, outputStr); 5 result = MessageUtil.parseXml(buffer.toString()); 6} catch (ConnectException ce) { 7 log.error("连接超时:"+ce.getMessage()); 8} catch (Exception e) { 9 log.error("https请求异常:"+ece.getMessage());10 }11return result;12 }
httpsRequest()这个方法在第一篇中
上面获取到的Map如果成功的话,里面就会有
1String return_code = map.get("return_code"); 2 if(StringUtils.isNotBlank(return_code) && return_code.equals("SUCCESS")){ 3 String return_msg = map.get("return_msg"); 4 if(StringUtils.isNotBlank(return_msg) && !return_msg.equals("OK")) { 5 return "统一下单错误!"; 6 } 7 }else{ 8 return "统一下单错误!"; 9 }1011 String prepay_Id = map.get("prepay_id");
这个prepay_id就是预支付的ID。后面支付需要它
如果觉得《微信公众号支付(二):统一下单》对你有帮助,请点赞、收藏,并留下你的观点哦!