java微信小程序调用支付接口

简介:微信小程序支付这里的坑还是有的,所以提醒各位在编写的一定要注意!!!

1.首先呢,你需要准备**openid,appid**,还有申请微信支付后要设置一个**32位的密钥**,需要先生成一个**sign**,得到**prepay_id**,然后再得到一个**paySign**,总之就是很墨迹,下面献上我的controller


//微信下单支付

@ResponseBody

@RequestMapping("doOrder")

public void doOrder(HttpServletRequest request, HttpServletResponse response) throws IOException, JDOMException {

request.setCharacterEncoding("UTF-8");

response.setCharacterEncoding("UTF-8");

//得到openid

String openid = request.getParameter("openid");

int fee = 0;

//得到小程序传过来的价格,注意这里的价格必须为整数,1代表1分,所以传过来的值必须*100;

if (null != request.getParameter("price")) {

fee = Integer.parseInt(request.getParameter("price").toString());

}

System.out.println(request.getParameter("price"));

System.out.println(fee);

//订单编号

String did = request.getParameter("did");

//订单标题

String title = request.getParameter("title");

//时间戳

String times = System.currentTimeMillis() + "";

SortedMap packageParams = new TreeMap();

packageParams.put("appid", "wxa**********2e2");

packageParams.put("mch_id", "1486425722");

packageParams.put("nonce_str", times);//时间戳

packageParams.put("body", title);//支付主体

packageParams.put("out_trade_no", did);//编号

packageParams.put("total_fee", fee);//价格

// packageParams.put("spbill_create_ip", getIp2(request));这里之前加了ip,但是总是获取sign失败,原因不明,之后就注释掉了

packageParams.put("notify_url", base+"/notify");//支付回调接口,用于支付成功后处理业务逻辑,小程序端支付success不能保证100%回调成功,建议采用后端异步回调处理方式,回调方法在最后

packageParams.put("trade_type", "JSAPI");//这个api有,固定的

packageParams.put("openid", openid);//openid

//获取sign

String sign = PayCommonUtil.createSign("UTF-8", packageParams, "x********************************4");//最后这个是自己设置的32位密钥

packageParams.put("sign", sign);

//转成XML

String requestXML = PayCommonUtil.getRequestXml(packageParams);

System.out.println(requestXML);

//得到含有prepay_id的XML

String resXml = HttpUtil.postData("https://api.mch.weixin.qq.com/pay/unifiedorder", requestXML);

System.out.println(resXml);

//解析XML存入Map

Map map = XMLUtil.doXMLParse(resXml);

System.out.println(map);

// String return_code = (String) map.get("return_code");

//得到prepay_id

String prepay_id = (String) map.get("prepay_id");

SortedMap packageP = new TreeMap();

packageP.put("appId", "wxa**********2e2");//!!!注意,这里是appId,上面是appid,真怀疑写这个东西的人。。。

packageP.put("nonceStr", times);//时间戳

packageP.put("package", "prepay_id=" + prepay_id);//必须把package写成 "prepay_id="+prepay_id这种形式

packageP.put("signType", "MD5");//paySign加密

packageP.put("timeStamp", (System.currentTimeMillis() / 1000) + "");

//得到paySign

String paySign = PayCommonUtil.createSign("UTF-8", packageP, "x********************************4");

packageP.put("paySign", paySign);

//将packageP数据返回给小程序

Gson gson = new Gson();

String json = gson.toJson(packageP);

PrintWriter pw = response.getWriter();

System.out.println(json);

pw.write(json);

pw.close();

}

```

2.下面是需要用到的工具类

(1).生成sign以及得到sign后生成XML工具类PayCommonUtil


public class PayCommonUtil {

/**

    * 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。

    * @return boolean

    */ 

    public static boolean isTenpaySign(String characterEncoding, SortedMap packageParams, String API_KEY) { 

        StringBuffer sb = new StringBuffer(); 

        Set es = packageParams.entrySet(); 

        Iterator it = es.iterator(); 

        while(it.hasNext()) { 

            Map.Entry entry = (Map.Entry)it.next(); 

            String k = (String)entry.getKey(); 

            String v = (String)entry.getValue(); 

            if(!"sign".equals(k) && null != v && !"".equals(v)) { 

                sb.append(k + "=" + v + "&"); 

            } 

        } 


        sb.append("key=" + API_KEY); 


        //算出摘要 

        String mysign = MD5.MD5Encode(sb.toString(), characterEncoding).toLowerCase(); 

        String tenpaySign = ((String)packageParams.get("sign")).toLowerCase(); 


        //System.out.println(tenpaySign + "    " + mysign); 

        return tenpaySign.equals(mysign); 

    } 


    /**

    * @author

    * @Description:sign签名

    * @param characterEncoding

    *            编码格式

    * @param parameters

    *            请求参数

    * @return

    */ 

    public static String createSign(String characterEncoding, SortedMap packageParams, String API_KEY) { 

        StringBuffer sb = new StringBuffer(); 

        Set es = packageParams.entrySet(); 

        Iterator it = es.iterator(); 

        while (it.hasNext()) { 

            Map.Entry entry = (Map.Entry) it.next(); 

            String k = entry.getKey().toString(); 

            String v = entry.getValue().toString(); 

            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) { 

                sb.append(k + "=" + v + "&"); 

            } 

        } 

        sb.append("key=" + API_KEY); 

        String sign = MD5.MD5Encode(sb.toString(), characterEncoding).toUpperCase(); 

        return sign; 

    } 


    /**

    * @author

    * @Description:将请求参数转换为xml格式的string

    * @param parameters

    *            请求参数

    * @return

    */ 

    public static String getRequestXml(SortedMap parameters) { 

        StringBuffer sb = new StringBuffer(); 

        sb.append(""); 

        Set es = parameters.entrySet(); 

        Iterator it = es.iterator(); 

        while (it.hasNext()) { 

            Map.Entry entry = (Map.Entry) it.next(); 

            String k = entry.getKey().toString(); 

            String v = entry.getValue().toString(); 

            if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) { 

                sb.append("<" + k + ">" + ""); 

            } else { 

                sb.append("<" + k + ">" + v + ""); 

            } 

        } 

        sb.append(""); 

        return sb.toString(); 

    } 


    /**

    * 取出一个指定长度大小的随机正整数.

    * 

    * @param length

    *            int 设定所取出随机数的长度。length小于11

    * @return int 返回生成的随机数。

    */ 

    public static int buildRandom(int length) { 

        int num = 1; 

        double random = Math.random(); 

        if (random < 0.1) { 

            random = random + 0.1; 

        } 

        for (int i = 0; i < length; i++) { 

            num = num * 10; 

        } 

        return (int) ((random * num)); 

    } 


    /**

    * 获取当前时间 yyyyMMddHHmmss

    * 

    * @return String

    */ 

    public static String getCurrTime() { 

        Date now = new Date(); 

        SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss"); 

        String s = outFormat.format(now); 

        return s; 

    } 

}

```

(2).访问官方接口得到含有prepay_id的XML工具类HttpUtil


public class HttpUtil {

//private static final Log logger = Logs.get(); 

    private final static int CONNECT_TIMEOUT = 5000; // in milliseconds 

    private final static String DEFAULT_ENCODING = "UTF-8"; 


    public static String postData(String urlStr, String data){ 

        return postData(urlStr, data, null); 

    } 


    public static String postData(String urlStr, String data, String contentType){ 

        BufferedReader reader = null; 

        try { 

            URL url = new URL(urlStr); 

            URLConnection conn = url.openConnection(); 

            conn.setDoOutput(true); 

            conn.setConnectTimeout(CONNECT_TIMEOUT); 

            conn.setReadTimeout(CONNECT_TIMEOUT); 

            if(contentType != null) 

                conn.setRequestProperty("content-type", contentType); 

            OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), DEFAULT_ENCODING); 

            if(data == null) 

                data = ""; 

            writer.write(data); 

            writer.flush(); 

            writer.close();   


            reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_ENCODING)); 

            StringBuilder sb = new StringBuilder(); 

            String line = null; 

            while ((line = reader.readLine()) != null) { 

                sb.append(line); 

                sb.append("\r\n"); 

            } 

            return sb.toString(); 

        } catch (IOException e) { 

            //logger.error("Error connecting to " + urlStr + ": " + e.getMessage()); 

        } finally { 

            try { 

                if (reader != null) 

                    reader.close(); 

            } catch (IOException e) { 

            } 

        } 

        return null; 

    } 

}

```

(3).解析XML工具类


public class XMLUtil {

public static Map doXMLParse(String strxml) throws JDOMException, IOException { 

        strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\""); 


        if(null == strxml || "".equals(strxml)) { 

            return null; 

        } 


        Map m = new HashMap(); 


        InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8")); 

        SAXBuilder builder = new SAXBuilder(); 

        Document doc = builder.build(in); 

        Element root = doc.getRootElement(); 

        List list = root.getChildren(); 

        Iterator it = list.iterator(); 

        while(it.hasNext()) { 

            Element e = (Element) it.next(); 

            String k = e.getName(); 

            String v = ""; 

            List children = e.getChildren(); 

            if(children.isEmpty()) { 

                v = e.getTextNormalize(); 

            } else { 

                v = XMLUtil.getChildrenText(children); 

            } 


            m.put(k, v); 

        } 


        //关闭流 

        in.close(); 


        return m; 

    } 


    /**

    * 获取子结点的xml

    * @param children

    * @return String

    */ 

    public static String getChildrenText(List children) { 

        StringBuffer sb = new StringBuffer(); 

        if(!children.isEmpty()) { 

            Iterator it = children.iterator(); 

            while(it.hasNext()) { 

                Element e = (Element) it.next(); 

                String name = e.getName(); 

                String value = e.getTextNormalize(); 

                List list = e.getChildren(); 

                sb.append("<" + name + ">"); 

                if(!list.isEmpty()) { 

                    sb.append(XMLUtil.getChildrenText(list)); 

                } 

                sb.append(value); 

                sb.append(""); 

            } 

        } 


        return sb.toString(); 

    } 

}

```

(4).MD5加密工具类


public class MD5 {

private static String byteArrayToHexString(byte b[]) {

        StringBuffer resultSb = new StringBuffer();

        for (int i = 0; i < b.length; i++)

            resultSb.append(byteToHexString(b[i]));

        return resultSb.toString();

    }

    private static String byteToHexString(byte b) {

        int n = b;

        if (n < 0)

            n += 256;

        int d1 = n / 16;

        int d2 = n % 16;

        return hexDigits[d1] + hexDigits[d2];

    }

    public static String MD5Encode(String origin, String charsetname) {

        String resultString = null;

        try {

            resultString = new String(origin);

            MessageDigest md = MessageDigest.getInstance("MD5");

            if (charsetname == null || "".equals(charsetname))

                resultString = byteArrayToHexString(md.digest(resultString

                        .getBytes()));

            else

                resultString = byteArrayToHexString(md.digest(resultString

                        .getBytes(charsetname)));

        } catch (Exception exception) {

        }

        return resultString;

    }


    private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",

        "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };

}

```

3.小程序支付函数


gopay: function () {

    var that = this

    wx.request({

      url: app.baseurl + 'doOrder',

      data: {

        'openid': wx.getStorageSync('openids'),

        'title': that.data.title,

        'did': that.data.did,

        'price': that.data.price*100

      },

      method: 'POST',

      header: {

        "content-type": 'application/x-www-form-urlencoded'

      },

      success: function (res) {

        console.log(res.data)

        console.log(res.data.timeStamp)

        console.log(res.data.nonceStr)

        console.log(res.data.package)

        console.log(res.data.paySign)

        wx.requestPayment({

          timeStamp: res.data.timeStamp,

          nonceStr: res.data.nonceStr,

          package: res.data.package,

          signType: res.data.signType,

          paySign: res.data.paySign,

          success: function (res) {

          console.log('支付调用成功',res)

          },

          fail: function (res) {

            console.log(res)

          }

        })

      }

    })

  }

```

4、支付成功回调


/**

    * 此函数会被执行多次,如果支付状态已经修改为已支付,则下次再调的时候判断是否已经支付,如果已经支付了,则什么也执行

    * @param request

    * @param response

    * @return

    * @throws IOException

    * @throws JDOMException

    */

    @RequestMapping(value = "notify")

    @ResponseBody

    public String notify(HttpServletRequest request, HttpServletResponse response) throws IOException {

    String resXml = "";

        System.out.println("微信支付回调");

//resultxml中含用户订单号等信息,解析后用于处理订单

        Map params = PayCommonUtil.doXMLParse(resultxml);

        if (!PayCommonUtil.isTenpaySign(params)) {

            // 支付失败

            resXml = "" + ""

                    + "" + " ";

        } else {

            System.out.println("==========付款成功==========");

            // ------------------------------

            // 处理业务开始

            // ------------------------------

            // 此处处理订单状态,结合自己的订单数据完成订单状态的更新

            // ------------------------------

//通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了

resXml = "" + ""

                    + "" + " ";

        }

        BufferedOutputStream out = new BufferedOutputStream(

                response.getOutputStream());

        out.write(resXml.getBytes());

        out.flush();

        out.close();

    }

```

结束啦,小程序支付的java后台就这些。

你可能感兴趣的:(java微信小程序调用支付接口)