天天看點

微信小程式微信支付的背景接口代碼

需要準備openid,appid,還有申請微信支付後要設定一個32位的密鑰,需要先生成一個sign,得到prepay_id,然後再得到一個paySign。

生成sign以及得到sign後生成XML工具類PayCommonUtil:

public class PayCommonUtil {

public static boolean isTenpaySign(String characterEncoding, SortedMap<String, String> 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 = MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase();

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

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

return tenpaySign.equals(mysign);

}

public static String createSign(String characterEncoding, SortedMap<Object, Object> 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 = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();

return sign;

}

public static String getRequestXml(SortedMap<Object, Object> parameters) {

StringBuffer sb = new StringBuffer();

sb.append("<xml>");

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 + ">" + "<![CDATA[" + v + "]]></" + k + ">");

} else {

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

}

}

sb.append("</xml>");

return sb.toString();

}

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));

}

public static String getCurrTime() {

Date now = new Date();

SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");

String s = outFormat.format(now);

return s;

}

public static String getRandomStringByLength(int length) {

String base = "abcdefghijklmnopqrstuvwxyz0123456789";

Random random = new Random();

StringBuffer sb = new StringBuffer();

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

int number = random.nextInt(base.length());

sb.append(base.charAt(number));

}

return sb.toString();

}

通路官方接口得到含有prepay_id的XML工具類HttpUtil的公共類:

public class HttpUtil {

        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) {  

            } finally {  

                try {  

                    if (reader != null)  

                        reader.close();  

                } catch (IOException e) {  

                }  

            }  

            return null;  

        }  

}

解析XML工具類:

public class XMLUtil {

     public static SortedMap<String, String> doXMLParse(String strxml) throws JDOMException, IOException {  

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

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

                return null;  

            }  

            SortedMap<String, String> m = new TreeMap<>();  

            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;  

        }  

        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("</" + name + ">");  

                }  

            }  

            return sb.toString();  

        }  

}

MD5加密工具類:

public class MD5Util {

    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" };

}

controller裡面的寫法:

@RequestMapping("/wechat/wxPay")

@EnableCORS

public class WxPayController extends WxBaseController {

@JbootrpcService

FinOrderService orderService;

@JbootrpcService

private FinOrderVideoService orderVideoService;

public void payOrder() {

// 得到openId

String openId = getWxOpenId();

if (!StrKit.isBlank(openId)) {

try {

String nonceStr = PayCommonUtil.getRandomStringByLength(32);

// 訂單id

String did = getPara("oid");

int price = 0;

// 得到小程式傳過來的價格,注意這裡的價格必須為整數,1代表1分,是以傳過來的值必須*100;

if (null != getParaToInt("price")) {

price = getParaToInt("price");

}

FinOrder order = orderService.findById(did);

SortedMap<Object, Object> packageParams = new TreeMap<>();

packageParams.put("appid", WxConsts.WECHAT_APPID);// 服務商ID

packageParams.put("mch_id", WxConsts.WECHAT_MCHID);// 商戶号

packageParams.put("nonce_str", nonceStr);// 随機字元串

packageParams.put("body", order.getBuName());// 商品描述

packageParams.put("out_trade_no", order.getOrdId());// 商戶訂單号

packageParams.put("total_fee", price);// 總金額

packageParams.put("notify_url", WxConsts.NOTIFY_URL);// 通知位址

packageParams.put("trade_type", WxConsts.TRADETYPE);// 交易類型 小程式取值:JSAPI

packageParams.put("openid", openId);// 使用者辨別

// 擷取sign

String sign = PayCommonUtil.createSign("UTF-8", packageParams, WxConsts.WECHAT_SECRET);// 最後這個是自己設定的32位密鑰

packageParams.put("sign", sign);

// 轉成XML

String requestXML = PayCommonUtil.getRequestXml(packageParams);

// 得到含有prepay_id的XML

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

// 解析XML存入Map

Map map = XMLUtil.doXMLParse(resXml);

// 得到prepay_id

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

SortedMap<Object, Object> packageP = new TreeMap<>();

packageP.put("appId", WxConsts.WECHAT_APPID);// !!!注意,這裡是appId,上面是appid,真懷疑寫這個東西的人。。。

packageP.put("nonceStr", nonceStr);// 時間戳

packageP.put("package", "prepay_id=" + prepayId);// 必須把package寫成 "prepay_id="+prepay_id這種形式

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

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

// 得到paySign

String paySign = PayCommonUtil.createSign("UTF-8", packageP, WxConsts.WECHAT_SECRET);

packageP.put("paySign", paySign);

// 将packageP資料傳回給小程式

renderJson(RestResult.buildSuccess(packageP));

} catch (Exception e) {

renderJson(RestResult.buildError());

}

} else {

renderJson(RestResult.buildError("使用者資訊擷取失敗"));

}

}

public void payNotify() {

try {

int ordId = getParaToInt("id");

String xmlString = "";

String lastXml = "";

xmlString = getPara();

// 先解析傳回的資料

SortedMap<String, String> dataMap = XMLUtil.doXMLParse(xmlString);

String returnCode = dataMap.get("return_code");

// 通信成功

if ("SUCCESS".equals(returnCode)) {

// 驗證通過才能記到流水表中,否則不計入

if (PayCommonUtil.isTenpaySign("UTF-8", dataMap, WxConsts.WECHAT_SECRET)) {

}

}

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

renderJson(RestResult.buildError("id不能為空"));

}

public void paySuccess() {

Long ordId = getParaToLong("id");

if (ordId != null) {

FinOrder model = new FinOrder();

model.setId(ordId);

model.setStatus(OrderStatus.PAID);

model.setStartTime(new Date());

boolean ret = orderService.update(model);

renderJson(RestResult.buildSuccess(ret));

} else {

renderJson(RestResult.buildError("id不能為空"));

}

}

}