微信支付开发教程之统一下单(补充2)

2017年08月15日 17:36 | 3408次浏览 作者原创 版权保护

调用微信公众支付的统一下单APIAPI地址: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("-","");
 }

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

总金额:不能为0

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

签名:

import java.io.Serializable;

public class PayInfo  implements Serializable{
    
    private static final long serialVersionUID = 5637164279924222380L;
    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 md5 = MessageDigest.getInstance("MD5");
       md5.reset();
       md5.update(signTemp.getBytes("UTF-8"));
       String sign = CommonUtil.byteToStr(md5.digest()).toUpperCase();
       return sign;
    }

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

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

/**
     * 将字节数组转换为十六进制字符串
     * 
     * @param byteArray
     * @return
     */
    public static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }

    /**
     * 将字节转换为十六进制字符串
     * 
     * @param btyes
     * @return
     */
    public static String byteToHexStr(byte bytes) {
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(bytes >>> 4) & 0X0F];
        tempArr[1] = Digit[bytes & 0X0F];

        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 = 0; i < ipAddr.length; i++) {  
            if (i > 0) {  
                ipAddrStr += ".";  
            }  
            ipAddrStr += ipAddr[i] & 0xFF;  
        }  
        return ipAddrStr;  
    }

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

 PayInfo pi = pu.createPayInfo(bo,"10.204.3.32","22");
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方法

  private static StringBuffer httpsRequest(String requestUrl, String requestMethod, String output)
            throws NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException, MalformedURLException,
            IOException, ProtocolException, UnsupportedEncodingException {
        
        URL url = new URL(requestUrl);
        HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
        
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setUseCaches(false);
        connection.setRequestMethod(requestMethod);
        if (null != output) {
            OutputStream outputStream = connection.getOutputStream();
            outputStream.write(output.getBytes("UTF-8"));
            outputStream.close();
        }

        // 从输入流读取返回内容
        InputStream inputStream = connection.getInputStream();
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        String str = null;
        StringBuffer buffer = new StringBuffer();
        while ((str = bufferedReader.readLine()) != null) {
            buffer.append(str);
        }

        bufferedReader.close();
        inputStreamReader.close();
        inputStream.close();
        inputStream = null;
        connection.disconnect();
        return buffer;
    } }

上面获取到的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。补充1这节课的支付需要它。


小说《我是全球混乱的源头》
此文章本站原创,地址 https://www.vxzsk.com/108.html   转载请注明出处!谢谢!

感觉本站内容不错,读后有收获?小额赞助,鼓励网站分享出更好的教程