HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

纯jsp实现微信支付,无需Java程序,完整绿色版复制即可用!

微信支付

本代码优点:无需依赖java程序,两个jsp文件走天下,方便多个项目复制使用,完整绿色无污染!

吐槽一下腾讯,给的示例代码太复杂不好调试,直接给个简单能跑通的多好,先能跑通再加复杂逻辑才是王道!

1、先要有微信开放平台的账号,并创建应用,审核通过。并且获取微信支付能力。
2、创建应用在填写Android的签名的时候要去掉冒号,并且小写(备注: 签名是用的md5 )
3、微信支付,一定要打包为apk 格式的文件,并且需要用到自己的keystore证书
4、打包好的apk文件,安装在手机测试

废话不多说,上代码:

1、HBuilder端js代码,放个按钮调用doWxPay()方法即可:


var channels = null;            
mui.plusReady(function() {  
    // 获取支付通道  
    plus.payment.getChannels(function(cs) {  
        channels = cs;  
    }, function(e) {  
        alert("获取支付通道失败:" + e.message);  
    });               
});  

var w=null;  
function doWxPay() {  
    if (w) return;   
    w = plus.nativeUI.showWaiting();  
    //获取支付通道  
    var channel;  
    for(var i in channels) {  
        if(channels[i].id == "wxpay") {  
            channel = channels[i];  
        }  
    }  
    mui.ajax('http://www.mywebsitexxx.com/pay_wx.jsp', {  
        data: {  
            total: "1", //支付金额1分  
            body: "Test", //支付界面标题  
            out_trade_no: "123456789"  //订单编号  
        },  
        type: 'post',  
        dataType: 'text',  
        timeout:20000,  
        success: function(data) {  
            w.close();  
            w = null;  
            data=data.replace(/\r\n/g,"").trim();  
            console.log(data);  
            plus.payment.request(channel, data, saveSuccess, saveFail);  
        },  
        error: function(xhr, errorType, error) {  
            w.close();  
            w = null;  
            alert(" error:"+error);  
        }  
    });  
}  

function saveSuccess(){  
    mui.toast("支付成功!");   
}  

function saveFail(error){  
    alert("支付失败!"+JSON.stringify(error));  
}  

2、服务端jsp代码pay_wx.jsp,放在网站根目录:


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>  
<%@page import="java.util.*"%>  
<%@page import="java.io.*"%>  
<%@page import="org.w3c.dom.*"%>  
<%@page import="javax.xml.parsers.*"%>  
<%@page import="javax.xml.transform.stream.*"%>  
<%@page import="javax.xml.transform.*"%>  
<%@page import="javax.xml.transform.dom.*"%>  
<%@page import="java.security.MessageDigest"%>  
<%@page import="org.apache.http.util.EntityUtils"%>  
<%@page import="org.apache.http.client.HttpClient"%>  
<%@page import="org.apache.http.*"%>  
<%@page import="org.apache.http.entity.StringEntity"%>  
<%@page import="org.apache.http.client.config.RequestConfig"%>  
<%@page import="org.apache.http.client.methods.HttpPost"%>  
<%@page import="org.apache.http.impl.client.HttpClientBuilder"%>  
<%@page import="org.apache.http.conn.ssl.SSLConnectionSocketFactory"%>  
<%@page import="org.apache.http.conn.socket.PlainConnectionSocketFactory"%>  
<%@page import="org.apache.http.conn.socket.ConnectionSocketFactory"%>  
<%@page import="org.apache.http.config.RegistryBuilder"%>  
<%@page import="org.apache.http.impl.conn.BasicHttpClientConnectionManager"%>  
<%!  
public static String AppID="wxea521866668888";//  
public static String MchID="13866668888";//商户id  
public static String Key="UNaaaaabbbb87349866668888";//支付秘钥key  
public String httpsPost(String url, String data) throws Exception {  
    BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager(  
                RegistryBuilder.<ConnectionSocketFactory>create()  
                        .register("http", PlainConnectionSocketFactory.getSocketFactory())  
                        .register("https", SSLConnectionSocketFactory.getSocketFactory())  
                        .build(),  
                null,  
                null,  
                null  
        );  

    HttpClient httpClient = HttpClientBuilder.create()  
            .setConnectionManager(connManager)  
            .build();  

    HttpPost httpPost = new HttpPost(url);  

    RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(200000).setConnectTimeout(200000).build();  
    httpPost.setConfig(requestConfig);  

    StringEntity postEntity = new StringEntity(data, "UTF-8");  
    httpPost.addHeader("Content-Type", "text/xml");  
    httpPost.setEntity(postEntity);  

    HttpResponse httpResponse = httpClient.execute(httpPost);  
    HttpEntity httpEntity = httpResponse.getEntity();  
    return EntityUtils.toString(httpEntity, "UTF-8");  
}  

public static String randomStr(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();  
}  

public static String MD5(String data) throws Exception {  
    java.security.MessageDigest md = MessageDigest.getInstance("MD5");  
    byte[] array = md.digest(data.getBytes("UTF-8"));  
    StringBuilder sb = new StringBuilder();  
    for (byte item : array) {  
        sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));  
    }  
    return sb.toString().toUpperCase();  
}  

public static String generateSignature(final Map<String, String> data, String key) throws Exception {  
    Set<String> keySet = data.keySet();  
    String[] keyArray = keySet.toArray(new String[keySet.size()]);  
    Arrays.sort(keyArray);  
    StringBuilder sb = new StringBuilder();  
    for (String k : keyArray) {  
        sb.append(k).append("=").append(data.get(k).trim()).append("&");  
    }  
    sb.append("key=").append(key);  
    return MD5(sb.toString());  
}  

public static String mapToXml(Map<String, String> data) throws Exception {  
    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();  
    DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();  
    org.w3c.dom.Document document = documentBuilder.newDocument();  
    org.w3c.dom.Element root = document.createElement("xml");  
    document.appendChild(root);  
    for (String key: data.keySet()) {  
        String value = data.get(key);  
        if (value == null) {  
            value = "";  
        }  
        value = value.trim();  
        org.w3c.dom.Element filed = document.createElement(key);  
        filed.appendChild(document.createTextNode(value));  
        root.appendChild(filed);  
    }  
    TransformerFactory tf = TransformerFactory.newInstance();  
    Transformer transformer = tf.newTransformer();  
    DOMSource source = new DOMSource(document);  
    transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");  
    transformer.setOutputProperty(OutputKeys.INDENT, "yes");  
    StringWriter writer = new StringWriter();  
    StreamResult result = new StreamResult(writer);  
    transformer.transform(source, result);  
    String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");  
    try {  
        writer.close();  
    }  
    catch (Exception ex) {  
    }  
    return output;  
}  
public static Map<String, String> xmlToMap(String strXML) throws Exception {  
    try {  
        Map<String, String> data = new HashMap<String, String>();  
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();  
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();  
        InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));  
        org.w3c.dom.Document doc = documentBuilder.parse(stream);  
        doc.getDocumentElement().normalize();  
        NodeList nodeList = doc.getDocumentElement().getChildNodes();  
        for (int idx = 0; idx < nodeList.getLength(); ++idx) {  
            Node node = nodeList.item(idx);  
            if (node.getNodeType() == Node.ELEMENT_NODE) {  
                org.w3c.dom.Element element = (org.w3c.dom.Element) node;  
                data.put(element.getNodeName(), element.getTextContent());  
            }  
        }  
        try {  
            stream.close();  
        } catch (Exception ex) {  
        }  
        return data;  
    } catch (Exception ex) {  
        throw ex;  
    }  

}  
%>  
<%  
HashMap<String, String> reqData = new HashMap<String, String>();  
reqData.put("appid", AppID);  
reqData.put("mch_id", MchID);  
reqData.put("body", request.getParameter("body"));// 商品描述  
reqData.put("out_trade_no", request.getParameter("out_trade_no")); // 商户订单号  
reqData.put("total_fee", request.getParameter("total"));//支付金额  
reqData.put("fee_type", "CNY");// 币种  
reqData.put("spbill_create_ip", request.getRemoteAddr());  
reqData.put("notify_url", "http://www.mywebsitexxx.com/webhook_wx.jsp");//微信回调notify页面  
reqData.put("trade_type", "APP");  
reqData.put("nonce_str",randomStr(20));  
String sign = generateSignature(reqData, Key);  
reqData.put("sign", sign);//打包签名          
String reqBody = mapToXml(reqData);  
String result = httpsPost("https://api.mch.weixin.qq.com/pay/unifiedorder", reqBody);  
//System.out.println(result);  
Map map = xmlToMap(result);  
String prepay_id = (String) map.get("prepay_id");  
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);  
String nonce_str = randomStr(20);  
String str = "appid=" + AppID + "&noncestr=" + nonce_str  
        + "&package=Sign=WXPay" + "&partnerid=" + MchID  
        + "&prepayid=" + prepay_id + "&timestamp=" + timestamp  
        + "&key=" + Key;  
String newSign = MD5(str);  
StringBuffer json = new StringBuffer();  
json.append("{\"appid\":\"");  
json.append(AppID);  
json.append("\",\"noncestr\":\"");  
json.append(nonce_str);  
json.append("\",\"package\":\"");  
json.append("Sign=WXPay");  
json.append("\",\"partnerid\":\"");  
json.append(MchID);  
json.append("\",\"prepayid\":\"");  
json.append(prepay_id);  
json.append("\",\"timestamp\":");  
json.append(timestamp);  
json.append(",\"sign\":\"");  
json.append(newSign);  
json.append("\"}");  
//System.out.println(json.toString());  
out.print(json.toString());  
%>  

3、微信回调notify页面jsp代码webhook_wx.jsp,放在网站根目录:


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>  
<%@page import="java.net.HttpURLConnection"%>  
<%@page import="java.net.URL"%>  
<%@page import="java.util.*"%>  
<%@page import="java.io.*"%>  
<%@page import="org.w3c.dom.*"%>  
<%@page import="javax.xml.parsers.*"%>  
<%!  
public static Map<String, String> xmlToMap(String strXML) throws Exception {  
    try {  
        Map<String, String> data = new HashMap<String, String>();  
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();  
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();  
        InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));  
        org.w3c.dom.Document doc = documentBuilder.parse(stream);  
        doc.getDocumentElement().normalize();  
        NodeList nodeList = doc.getDocumentElement().getChildNodes();  
        for (int idx = 0; idx < nodeList.getLength(); ++idx) {  
            Node node = nodeList.item(idx);  
            if (node.getNodeType() == Node.ELEMENT_NODE) {  
                org.w3c.dom.Element element = (org.w3c.dom.Element) node;  
                data.put(element.getNodeName(), element.getTextContent());  
            }  
        }  
        try {  
            stream.close();  
        } catch (Exception ex) {  
        }  
        return data;  
    } catch (Exception ex) {  
        throw ex;  
    }  
}  
%>  
<%  
StringBuffer xmlStr = new StringBuffer();  
String line = null;  
try {  
    request.setCharacterEncoding("utf-8");  
    BufferedReader reader = request.getReader();  
    while ((line = reader.readLine()) != null) {  
        xmlStr.append(line);  
    }  
} catch (Exception e) {  
    e.printStackTrace();  
}  
System.out.println("微信支付:"+xmlStr);  
Map data = xmlToMap(xmlStr.toString());  
if("SUCCESS".equals(data.get("return_code"))   
        && "SUCCESS".equals(data.get("result_code"))){  
    Double totalFee = new Double(data.get("total_fee").toString())/100;  
    //TODO:这里加判断逻辑,编写更新订单状态的代码,或直接调用写好的Java类  
    System.out.println(totalFee );  
        out.println("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");  
    } catch (Exception e) {  
        e.printStackTrace();  
    }     
}else{  
    out.println("ERROR");  
}  
%>  

完毕,打包apk即可测试。
注:各种依赖jar包还得自行去下载。

继续阅读 »

本代码优点:无需依赖java程序,两个jsp文件走天下,方便多个项目复制使用,完整绿色无污染!

吐槽一下腾讯,给的示例代码太复杂不好调试,直接给个简单能跑通的多好,先能跑通再加复杂逻辑才是王道!

1、先要有微信开放平台的账号,并创建应用,审核通过。并且获取微信支付能力。
2、创建应用在填写Android的签名的时候要去掉冒号,并且小写(备注: 签名是用的md5 )
3、微信支付,一定要打包为apk 格式的文件,并且需要用到自己的keystore证书
4、打包好的apk文件,安装在手机测试

废话不多说,上代码:

1、HBuilder端js代码,放个按钮调用doWxPay()方法即可:


var channels = null;            
mui.plusReady(function() {  
    // 获取支付通道  
    plus.payment.getChannels(function(cs) {  
        channels = cs;  
    }, function(e) {  
        alert("获取支付通道失败:" + e.message);  
    });               
});  

var w=null;  
function doWxPay() {  
    if (w) return;   
    w = plus.nativeUI.showWaiting();  
    //获取支付通道  
    var channel;  
    for(var i in channels) {  
        if(channels[i].id == "wxpay") {  
            channel = channels[i];  
        }  
    }  
    mui.ajax('http://www.mywebsitexxx.com/pay_wx.jsp', {  
        data: {  
            total: "1", //支付金额1分  
            body: "Test", //支付界面标题  
            out_trade_no: "123456789"  //订单编号  
        },  
        type: 'post',  
        dataType: 'text',  
        timeout:20000,  
        success: function(data) {  
            w.close();  
            w = null;  
            data=data.replace(/\r\n/g,"").trim();  
            console.log(data);  
            plus.payment.request(channel, data, saveSuccess, saveFail);  
        },  
        error: function(xhr, errorType, error) {  
            w.close();  
            w = null;  
            alert(" error:"+error);  
        }  
    });  
}  

function saveSuccess(){  
    mui.toast("支付成功!");   
}  

function saveFail(error){  
    alert("支付失败!"+JSON.stringify(error));  
}  

2、服务端jsp代码pay_wx.jsp,放在网站根目录:


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>  
<%@page import="java.util.*"%>  
<%@page import="java.io.*"%>  
<%@page import="org.w3c.dom.*"%>  
<%@page import="javax.xml.parsers.*"%>  
<%@page import="javax.xml.transform.stream.*"%>  
<%@page import="javax.xml.transform.*"%>  
<%@page import="javax.xml.transform.dom.*"%>  
<%@page import="java.security.MessageDigest"%>  
<%@page import="org.apache.http.util.EntityUtils"%>  
<%@page import="org.apache.http.client.HttpClient"%>  
<%@page import="org.apache.http.*"%>  
<%@page import="org.apache.http.entity.StringEntity"%>  
<%@page import="org.apache.http.client.config.RequestConfig"%>  
<%@page import="org.apache.http.client.methods.HttpPost"%>  
<%@page import="org.apache.http.impl.client.HttpClientBuilder"%>  
<%@page import="org.apache.http.conn.ssl.SSLConnectionSocketFactory"%>  
<%@page import="org.apache.http.conn.socket.PlainConnectionSocketFactory"%>  
<%@page import="org.apache.http.conn.socket.ConnectionSocketFactory"%>  
<%@page import="org.apache.http.config.RegistryBuilder"%>  
<%@page import="org.apache.http.impl.conn.BasicHttpClientConnectionManager"%>  
<%!  
public static String AppID="wxea521866668888";//  
public static String MchID="13866668888";//商户id  
public static String Key="UNaaaaabbbb87349866668888";//支付秘钥key  
public String httpsPost(String url, String data) throws Exception {  
    BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager(  
                RegistryBuilder.<ConnectionSocketFactory>create()  
                        .register("http", PlainConnectionSocketFactory.getSocketFactory())  
                        .register("https", SSLConnectionSocketFactory.getSocketFactory())  
                        .build(),  
                null,  
                null,  
                null  
        );  

    HttpClient httpClient = HttpClientBuilder.create()  
            .setConnectionManager(connManager)  
            .build();  

    HttpPost httpPost = new HttpPost(url);  

    RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(200000).setConnectTimeout(200000).build();  
    httpPost.setConfig(requestConfig);  

    StringEntity postEntity = new StringEntity(data, "UTF-8");  
    httpPost.addHeader("Content-Type", "text/xml");  
    httpPost.setEntity(postEntity);  

    HttpResponse httpResponse = httpClient.execute(httpPost);  
    HttpEntity httpEntity = httpResponse.getEntity();  
    return EntityUtils.toString(httpEntity, "UTF-8");  
}  

public static String randomStr(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();  
}  

public static String MD5(String data) throws Exception {  
    java.security.MessageDigest md = MessageDigest.getInstance("MD5");  
    byte[] array = md.digest(data.getBytes("UTF-8"));  
    StringBuilder sb = new StringBuilder();  
    for (byte item : array) {  
        sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));  
    }  
    return sb.toString().toUpperCase();  
}  

public static String generateSignature(final Map<String, String> data, String key) throws Exception {  
    Set<String> keySet = data.keySet();  
    String[] keyArray = keySet.toArray(new String[keySet.size()]);  
    Arrays.sort(keyArray);  
    StringBuilder sb = new StringBuilder();  
    for (String k : keyArray) {  
        sb.append(k).append("=").append(data.get(k).trim()).append("&");  
    }  
    sb.append("key=").append(key);  
    return MD5(sb.toString());  
}  

public static String mapToXml(Map<String, String> data) throws Exception {  
    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();  
    DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();  
    org.w3c.dom.Document document = documentBuilder.newDocument();  
    org.w3c.dom.Element root = document.createElement("xml");  
    document.appendChild(root);  
    for (String key: data.keySet()) {  
        String value = data.get(key);  
        if (value == null) {  
            value = "";  
        }  
        value = value.trim();  
        org.w3c.dom.Element filed = document.createElement(key);  
        filed.appendChild(document.createTextNode(value));  
        root.appendChild(filed);  
    }  
    TransformerFactory tf = TransformerFactory.newInstance();  
    Transformer transformer = tf.newTransformer();  
    DOMSource source = new DOMSource(document);  
    transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");  
    transformer.setOutputProperty(OutputKeys.INDENT, "yes");  
    StringWriter writer = new StringWriter();  
    StreamResult result = new StreamResult(writer);  
    transformer.transform(source, result);  
    String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");  
    try {  
        writer.close();  
    }  
    catch (Exception ex) {  
    }  
    return output;  
}  
public static Map<String, String> xmlToMap(String strXML) throws Exception {  
    try {  
        Map<String, String> data = new HashMap<String, String>();  
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();  
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();  
        InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));  
        org.w3c.dom.Document doc = documentBuilder.parse(stream);  
        doc.getDocumentElement().normalize();  
        NodeList nodeList = doc.getDocumentElement().getChildNodes();  
        for (int idx = 0; idx < nodeList.getLength(); ++idx) {  
            Node node = nodeList.item(idx);  
            if (node.getNodeType() == Node.ELEMENT_NODE) {  
                org.w3c.dom.Element element = (org.w3c.dom.Element) node;  
                data.put(element.getNodeName(), element.getTextContent());  
            }  
        }  
        try {  
            stream.close();  
        } catch (Exception ex) {  
        }  
        return data;  
    } catch (Exception ex) {  
        throw ex;  
    }  

}  
%>  
<%  
HashMap<String, String> reqData = new HashMap<String, String>();  
reqData.put("appid", AppID);  
reqData.put("mch_id", MchID);  
reqData.put("body", request.getParameter("body"));// 商品描述  
reqData.put("out_trade_no", request.getParameter("out_trade_no")); // 商户订单号  
reqData.put("total_fee", request.getParameter("total"));//支付金额  
reqData.put("fee_type", "CNY");// 币种  
reqData.put("spbill_create_ip", request.getRemoteAddr());  
reqData.put("notify_url", "http://www.mywebsitexxx.com/webhook_wx.jsp");//微信回调notify页面  
reqData.put("trade_type", "APP");  
reqData.put("nonce_str",randomStr(20));  
String sign = generateSignature(reqData, Key);  
reqData.put("sign", sign);//打包签名          
String reqBody = mapToXml(reqData);  
String result = httpsPost("https://api.mch.weixin.qq.com/pay/unifiedorder", reqBody);  
//System.out.println(result);  
Map map = xmlToMap(result);  
String prepay_id = (String) map.get("prepay_id");  
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);  
String nonce_str = randomStr(20);  
String str = "appid=" + AppID + "&noncestr=" + nonce_str  
        + "&package=Sign=WXPay" + "&partnerid=" + MchID  
        + "&prepayid=" + prepay_id + "&timestamp=" + timestamp  
        + "&key=" + Key;  
String newSign = MD5(str);  
StringBuffer json = new StringBuffer();  
json.append("{\"appid\":\"");  
json.append(AppID);  
json.append("\",\"noncestr\":\"");  
json.append(nonce_str);  
json.append("\",\"package\":\"");  
json.append("Sign=WXPay");  
json.append("\",\"partnerid\":\"");  
json.append(MchID);  
json.append("\",\"prepayid\":\"");  
json.append(prepay_id);  
json.append("\",\"timestamp\":");  
json.append(timestamp);  
json.append(",\"sign\":\"");  
json.append(newSign);  
json.append("\"}");  
//System.out.println(json.toString());  
out.print(json.toString());  
%>  

3、微信回调notify页面jsp代码webhook_wx.jsp,放在网站根目录:


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>  
<%@page import="java.net.HttpURLConnection"%>  
<%@page import="java.net.URL"%>  
<%@page import="java.util.*"%>  
<%@page import="java.io.*"%>  
<%@page import="org.w3c.dom.*"%>  
<%@page import="javax.xml.parsers.*"%>  
<%!  
public static Map<String, String> xmlToMap(String strXML) throws Exception {  
    try {  
        Map<String, String> data = new HashMap<String, String>();  
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();  
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();  
        InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));  
        org.w3c.dom.Document doc = documentBuilder.parse(stream);  
        doc.getDocumentElement().normalize();  
        NodeList nodeList = doc.getDocumentElement().getChildNodes();  
        for (int idx = 0; idx < nodeList.getLength(); ++idx) {  
            Node node = nodeList.item(idx);  
            if (node.getNodeType() == Node.ELEMENT_NODE) {  
                org.w3c.dom.Element element = (org.w3c.dom.Element) node;  
                data.put(element.getNodeName(), element.getTextContent());  
            }  
        }  
        try {  
            stream.close();  
        } catch (Exception ex) {  
        }  
        return data;  
    } catch (Exception ex) {  
        throw ex;  
    }  
}  
%>  
<%  
StringBuffer xmlStr = new StringBuffer();  
String line = null;  
try {  
    request.setCharacterEncoding("utf-8");  
    BufferedReader reader = request.getReader();  
    while ((line = reader.readLine()) != null) {  
        xmlStr.append(line);  
    }  
} catch (Exception e) {  
    e.printStackTrace();  
}  
System.out.println("微信支付:"+xmlStr);  
Map data = xmlToMap(xmlStr.toString());  
if("SUCCESS".equals(data.get("return_code"))   
        && "SUCCESS".equals(data.get("result_code"))){  
    Double totalFee = new Double(data.get("total_fee").toString())/100;  
    //TODO:这里加判断逻辑,编写更新订单状态的代码,或直接调用写好的Java类  
    System.out.println(totalFee );  
        out.println("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");  
    } catch (Exception e) {  
        e.printStackTrace();  
    }     
}else{  
    out.println("ERROR");  
}  
%>  

完毕,打包apk即可测试。
注:各种依赖jar包还得自行去下载。

收起阅读 »

快捷键混乱,设置无效

添加/取消缩进的快捷键和tab 切换的快捷键混乱在一起了,来提交BUG还说积分不够。。。尼玛真纠结被浪费的时间。。。

添加/取消缩进的快捷键和tab 切换的快捷键混乱在一起了,来提交BUG还说积分不够。。。尼玛真纠结被浪费的时间。。。

Hbuilder+MUI远程获取服务器数据显示出来

MUI前端代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title></title>
<script src="js/mui.min.js"></script>
<link href="css/mui.min.css" rel="stylesheet"/>
</head>
<body>
<header class="mui-bar mui-bar-nav">
<h1 class="mui-title">内容展示页</h1>
</header>
<div class="mui-content">
<div id="con">在这里就是我们要插入的远程数据内容(html)</div>
</div>

<script type="text/javascript">       
    /*  
     * @auth:韦小宝  
     * @weixin:8788981  
     * @qq:8788981  
     */  
    mui.init();  
    mui.post('http://localhost/ThinkPHPAPI/',{  
        nid:'1'//这里通过POST发送数据到PHP服务器用以验证  
        },function(data){  
            //服务器返回响应,根据响应结果,分析是否登录成功;          
            var d=eval(data);   //转换成javascript对象  
            var c=document.getElementById('con');                 
            for(var i in d){                      
                c.innerHTML=d[i].content;  
            }    
        },'json');  
</script>  

</body>
</html>
PHP接口实现代码:
代码基于thinkphp
<?php
/*

  • @qq/weixin:8788981
  • @auth:weixiaobao
    /
    class IndexAction extends Action {
    public function index(){
    header("Content-Type:text/html; charset=utf-8");
    header('Content-type:text/json');//输出为json格式页
    header("Access-Control-Allow-Origin:
    "); // 允许任意域名发起的跨域请求
    header('Access-Control-Allow-Headers: X-Requested-With,X_Requested_With');

    /*  判断手机端发过来的信息(预先存储手机硬件信息)再进行数据的查询判断  
     *  这里只是通过明文的查询,不作动态的优化  
     *  希望大家发挥自己的想象力,做相应的远程判断,开发更快、更安全的APP  
     */  
    
    if($_POST['nid']==1){  
        $Con=M("News_content");  
        $list=$Con->where("nid=1")->select();  
        echo json_encode($list); //输出json  
    }  

    }
    }
    ?>

继续阅读 »

MUI前端代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title></title>
<script src="js/mui.min.js"></script>
<link href="css/mui.min.css" rel="stylesheet"/>
</head>
<body>
<header class="mui-bar mui-bar-nav">
<h1 class="mui-title">内容展示页</h1>
</header>
<div class="mui-content">
<div id="con">在这里就是我们要插入的远程数据内容(html)</div>
</div>

<script type="text/javascript">       
    /*  
     * @auth:韦小宝  
     * @weixin:8788981  
     * @qq:8788981  
     */  
    mui.init();  
    mui.post('http://localhost/ThinkPHPAPI/',{  
        nid:'1'//这里通过POST发送数据到PHP服务器用以验证  
        },function(data){  
            //服务器返回响应,根据响应结果,分析是否登录成功;          
            var d=eval(data);   //转换成javascript对象  
            var c=document.getElementById('con');                 
            for(var i in d){                      
                c.innerHTML=d[i].content;  
            }    
        },'json');  
</script>  

</body>
</html>
PHP接口实现代码:
代码基于thinkphp
<?php
/*

  • @qq/weixin:8788981
  • @auth:weixiaobao
    /
    class IndexAction extends Action {
    public function index(){
    header("Content-Type:text/html; charset=utf-8");
    header('Content-type:text/json');//输出为json格式页
    header("Access-Control-Allow-Origin:
    "); // 允许任意域名发起的跨域请求
    header('Access-Control-Allow-Headers: X-Requested-With,X_Requested_With');

    /*  判断手机端发过来的信息(预先存储手机硬件信息)再进行数据的查询判断  
     *  这里只是通过明文的查询,不作动态的优化  
     *  希望大家发挥自己的想象力,做相应的远程判断,开发更快、更安全的APP  
     */  
    
    if($_POST['nid']==1){  
        $Con=M("News_content");  
        $list=$Con->where("nid=1")->select();  
        echo json_encode($list); //输出json  
    }  

    }
    }
    ?>

收起阅读 »

登录失败 -2

想学的联系我,我教你,联系QQ:2951268624

想学的联系我,我教你,联系QQ:2951268624

带右侧按钮的搜索栏的实现

搜索

目前mui官方只有一个搜索栏示例供参考,但是只是一个输入框而已,很多时候这并不是我们想要的。
我们有时只是想要一个常规的搜索栏:左边输入框,右边紧接一个确定按钮。
在这里分享一下,我个人的代母,效果图如下:

实现的代码:
<!-- 搜索栏 -->
<div style="display:inline-flex; width:100%; padding-left:1px; padding-right:1px;">
<div class="mui-input-row" style="height:40px; flex-grow:4;">
<input type="text" class="mui-input-clear s_font-size2" placeholder="医院名称" maxlength="100" style="height:100%; padding-right:32px;"/>
</div>
<div style="height:40px; flex-grow:1;">
<input type="button" value="搜索" class="u_btn" style="width:100%; height:100%;"/>
</div>
</div>

继续阅读 »

目前mui官方只有一个搜索栏示例供参考,但是只是一个输入框而已,很多时候这并不是我们想要的。
我们有时只是想要一个常规的搜索栏:左边输入框,右边紧接一个确定按钮。
在这里分享一下,我个人的代母,效果图如下:

实现的代码:
<!-- 搜索栏 -->
<div style="display:inline-flex; width:100%; padding-left:1px; padding-right:1px;">
<div class="mui-input-row" style="height:40px; flex-grow:4;">
<input type="text" class="mui-input-clear s_font-size2" placeholder="医院名称" maxlength="100" style="height:100%; padding-right:32px;"/>
</div>
<div style="height:40px; flex-grow:1;">
<input type="button" value="搜索" class="u_btn" style="width:100%; height:100%;"/>
</div>
</div>

收起阅读 »

一种更柔和的底部消息提醒控件示例

消息提醒

一图胜千言:

相对中间弹框的方式,这是一种更柔和的提醒方式,不打断用户在主界面的操作过程;

实现方式很简单,生成一个固定底部的DIV即可,DOM结构如下:

<div class="message bottom">  
    <div class="icon">  
        <span class="mui-icon mui-icon-info"></span>  
    </div>  
    <p class="content">应用当前版本过低,存在安全漏洞,请升级至最新版</p>  
    <div class="action">  
        <button type="button" class="mui-btn mui-btn-blue mui-btn-link">取消</button>  
        <button id="install" type="button" class="mui-btn mui-btn-blue">立即升级</button>  
    </div>  
</div>

其余就是css代码,定义组件布局

.message {  
    background-color: #fff;  
    z-index: 99;  
    box-shadow: 0px -5px 5px 0px rgba(150, 150, 150, .2);  
}  

.message.bottom {  
    position: fixed;  
    padding: 15px;  
    bottom: 0;  
    left: 0px;  
    right: 0px;  
}  

.message .icon {  
    width: 42px;  
    height: 42px;  
    float: left;  
    text-align: center;  
}  

.message .content {  
    padding-left: 55px;  
    font-size: 13px;  
}  

.icon .mui-icon {  
    font-weight: 28px;  
    font-weight: 700;  
    line-height: 42px;  
    color: #007AFF;  
}  

.action {  
    text-align: right;  
    padding-right: 2px;  
    margin-top: 18px;  
}

完整代码示例参考github源码

继续阅读 »

一图胜千言:

相对中间弹框的方式,这是一种更柔和的提醒方式,不打断用户在主界面的操作过程;

实现方式很简单,生成一个固定底部的DIV即可,DOM结构如下:

<div class="message bottom">  
    <div class="icon">  
        <span class="mui-icon mui-icon-info"></span>  
    </div>  
    <p class="content">应用当前版本过低,存在安全漏洞,请升级至最新版</p>  
    <div class="action">  
        <button type="button" class="mui-btn mui-btn-blue mui-btn-link">取消</button>  
        <button id="install" type="button" class="mui-btn mui-btn-blue">立即升级</button>  
    </div>  
</div>

其余就是css代码,定义组件布局

.message {  
    background-color: #fff;  
    z-index: 99;  
    box-shadow: 0px -5px 5px 0px rgba(150, 150, 150, .2);  
}  

.message.bottom {  
    position: fixed;  
    padding: 15px;  
    bottom: 0;  
    left: 0px;  
    right: 0px;  
}  

.message .icon {  
    width: 42px;  
    height: 42px;  
    float: left;  
    text-align: center;  
}  

.message .content {  
    padding-left: 55px;  
    font-size: 13px;  
}  

.icon .mui-icon {  
    font-weight: 28px;  
    font-weight: 700;  
    line-height: 42px;  
    color: #007AFF;  
}  

.action {  
    text-align: right;  
    padding-right: 2px;  
    margin-top: 18px;  
}

完整代码示例参考github源码

收起阅读 »

vue与刷新组件冲突问题

下拉刷新 Vue

在vue与刷新组件共同使用时,pullrefresh组件会阻止事件冒泡,导致无法点击的问题。
注释

if (e.touches && e.touches.length && e.touches[0].clientX > 30) {  
        e.target && !this._preventDefaultException(e.target, this.options.preventDefaultException) && e.preventDefault();  
}
继续阅读 »

在vue与刷新组件共同使用时,pullrefresh组件会阻止事件冒泡,导致无法点击的问题。
注释

if (e.touches && e.touches.length && e.touches[0].clientX > 30) {  
        e.target && !this._preventDefaultException(e.target, this.options.preventDefaultException) && e.preventDefault();  
}
收起阅读 »

关于NET-C#开发HBuillder的APP支付(支付宝支付+微信支付)经验分享

NET-C#开发HBuillder的APP ,QQ群 :661996236

最近由于连续太多人找我咨询NET_C#开发支付功能,请求协助和demo,所以本人在此简单分享一下,其实在本社区内,已有一部分代码了。

链接:C#配置支付宝信息

APP前端开发调用代码示例,由于是项目部分代码,请自行完善APP前端支付代码,返回测试数据,只是演示,数据自行测试输出,由于
备注 : 获取支付通道

APP端调用代码说明


    //定义支付通道  
    var channel = null;  
    var channelali = null;  
    var channelwx = null;  

    //获取支付通道的方法  
    function getChannels() {  
        plus.payment.getChannels(function (channels) {  
            channelali = channels[0];  
            channelwx = channels[1];  

//          for (var i = 0; i < channels.length; i++) {  
//                 
//              //if(mr=="支付宝")  
//              //{  
//                  if (channels[i].id == "alipay")   
//                  { //wxpay  //alipay  
//                      channelali = channels[i];   
//                  }  
//              //}   
//              //if(mr=="微信")  
//              //{  
//                 if (channels[i].id == "wxpay")  
//                 { //wxpay  //alipay  
//                     channelwx = channels[i];   
//                 }  
//            // }  
//          }  
            // plus.ui.toast("使用支付方式:" + channel.id);  
        }, function (e) {  
            plus.ui.toast("获取支付通道失败!");  
            console.log("获取支付通道失败!");  
        })  
    }  

//支付事件  
 mui('.gouwuche').on('tap', '#waitpay', function (event) {  
        channel = null;  

        var payv = g("pay").value;  
        console.log(payv);  
        if (payv == '2') {  
            urlpay = "OrderPay/GetWxPayInfo";  
            console.log(urlpay);  
        } else {  
            urlpay = "OrderPay/PayMent";  
            console.log(urlpay);  
        }  
        //获取支付通道  
        // getChannels( );  
        // console.log(channel.id);  
        //apiurl + "AliPay/testsign" OrderPay/PayMent   Weixin/GetPayInfo  

        postwait(apiurl + urlpay, returnJson({  
                    orderid: order_no,  
                    type: '3'  
                }), function (data) {  
                    //console.log(data);  
                    var err = JSON.parse(data).err;  
                    if (err == 0) {  
                        var appdata = JSON.parse(data).data;  
                        //console.log(m);  
                        getChannels();  
                        var pay = g("pay").value;  
                        console.log(appdata.msg);  
                        if (pay == 1)   //channel.id== 'alipay')  
                        {  
                            appdata = appdata.msg; //JSON.parse(appdata).msg; //支付宝  
                            channel = channelali;  
                            console.log(channelali.id);  
                        } else {  
                            channel = channelwx;  
                            console.log(channelwx.id);  
                            // console.log("==微信信息=="+ JSON.stringify(appdata));  
                            // appdata = JSON.stringify(appdata); //微信  
                        }  
                        // console.log("==支付信息=="+ appdata);  
                        //appdata='{"appid":"wx123456789,"noncestr":"QtyOdJUspxLGOG5c","package":"Sign=WXPay","partnerid":"12345678","prepayid":"wx20179876543234","timestamp":1496823681,"sign":"DD2D77CE3A770C497A03B3BCEABEF12C"}';  

                        plus.payment.request(channel, appdata, function (result) {  

                                // 弹出系统提示对话框  
                                //mui.toast("支付成功!");   
                                plus.nativeUI.alert( "支付成功!",  
                                 function()  
                                 {   
                                     //修改订单状态   
                                     postwait(apiurl + "OrderPay/UpdateOrderStatus", returnJson({  
                                            orderid: order_no,  
                                            type: 3  
                                        }), function (data) {  
                                            console.log("修改:"+data);  

                                            //openwindows("../../index.html","index.html");   
                                            //alert('22');   
                                            //alert("end");  

                                             var obj = plus.webview.getWebviewById("shopsDetails");  
                                             if(obj!=null){ obj.reload(); }  

                                             plus.webview.getLaunchWebview().evalJS("orderlist();");     
                                                                             plus.webview.getLaunchWebview().show();   

                                            }  
                                        );   
                                  }, "测试支付", "确认" );    

                        }, function (error) {  

                            if (error.code == 62001) {  
                                mui.toast("您放弃支付.");  
                                // mui.back();  
                            } else {  
                                //alert(error.message);  
                                mui.toast("请前往订单管理尝试支付.");   
                                // plus.nativeUI.alert("支付失败", null,  "请前往订单管理尝试支付,支付失败:"+error.code  );   
                            }  
                            var obj = plus.webview.getWebviewById("shopsDetails");  
                            if(obj!=null){ obj.reload(); }  

                             plus.webview.getLaunchWebview().evalJS("orderlist();");     
                             plus.webview.getLaunchWebview().show();   
                        });  

                   //  

                    } else {  
                        var msg = JSON.parse(data).msg;   //JSON.parse(JSON.parse(data).data).error; //JSON.parse(data).msg;  
                        mui.toast(msg);  
                    }  
                }  
        );  

      //跳转   
       var obj = plus.webview.getWebviewById("middle_main.html");  
       if(obj!=null)  
         obj.reload();  

       //plus.webview.currentWebview().close();   
       openwindows("/pages/home/middle_main.html", "middle_main.html", { address_id: 1 });   

    });

NET-C#支付宝代码验证以及生成支付字符串

支付宝支付

支付宝参考:
链接:C#配置支付宝信息

本文使用C# WebAPI方式

  /// <summary>  
        /// 获取支付信息  
        /// </summary>  
        /// <param name="_amount"></param>  
        /// <returns></returns>  
        [HttpPost, Route("Alipay/GetPayInfo")]  
        public string GetPayInfo(string orderid)//_amount:付款金额  
        {  
            string strJson = string.Empty;  
            try  
            {  
                //string _amount = "0.01";  
                string orderInfo = GetOrderInfoWithOutEncode(orderid);  
                // 对订单做RSA 签名  
                string sign = RSAFromPkcs8.sign(orderInfo, Config.privtekey, "utf-8");  
                //仅需对sign做URL编码  
                sign = HttpUtility.UrlEncode(sign, Encoding.UTF8);  
                string payInfo = GetOrderInfoWithEncode() + "&sign=" + sign;  
                strJson = payInfo.Replace("+", "%20");//日期那里会有一个空格(2017-01-05 11:11:11)转化为+,所以这里要替换一下  
                DTcms.Common.FileOperate.WriteLogInfo("", "支付宝串:" + strJson);  
            }  
            catch (Exception ex)  
            {  
                DTcms.Common.FileOperate.WriteLogInfo("", "GetPayInfo Exception:" + ex.Message);  
                //FileLog.WriteLog(ex.ToString());  

            }  
            return strJson;  
        }  

      /// <summary>  
        /// 不包含Encode的字符串拼接  
        /// </summary>  
        /// <param name="price"></param>  
        /// <returns></returns>  
        public string GetOrderInfoWithOutEncode(string orderid)  
        {  
            //  DTcms.Common.FileOperate.WriteLogInfo("", "支付宝串:" + strJson);  

            PayInfo.Add("app_id", Config.app_id);  
            PayInfo.Add("biz_content", GetBizContent(orderid));  
            PayInfo.Add("charset", "utf-8");  
            PayInfo.Add("format", "json");  
            PayInfo.Add("method", "alipay.trade.app.pay");  
            PayInfo.Add("notify_url", "http://www.baidu.com/OrderPay/PayUpdateStatus");  
            PayInfo.Add("sign_type", "RSA");  
            PayInfo.Add("timestamp", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));  
            PayInfo.Add("version", "1.0");  
            string strUrl = BuildQueryWithOutEncode(PayInfo);  
            return strUrl;  
        }  

        /// <summary>  
        /// 获取支付内容详情  
        /// </summary>  
        /// <param name="total_amount"></param>  
        /// <returns></returns>  
        public string GetBizContent(string orderid)  
        {  
            string strSql = string.Format(@"select dt_shop_orders.id,dt_shop_orders.order_no,dt_shop_orders.order_amount,dt_shop_order_goods.goods_title from dt_shop_orders  
                                            left join dt_shop_order_goods on dt_shop_orders.id  = dt_shop_order_goods.order_id where dt_shop_orders.id = {0}", orderid);  
            DataTable dt = DbHelperSQL.Query(strSql).Tables[0];  
            Dictionary<string, string> biz_content_info = new Dictionary<string, string>();  
            biz_content_info.Add("timeout_express", "30m");//该笔订单允许的最晚付款时间,逾期将关闭交易。  
            biz_content_info.Add("seller_id", "");//收款支付宝用户ID。 如果该值为空,则默认为商户签约账号对应的支付宝用户ID  
            biz_content_info.Add("product_code", "QUICK_MSECURITY_PAY");//销售产品码,商家和支付宝签约的产品码,为固定值QUICK_MSECURITY_PAY  
            biz_content_info.Add("total_amount", dt.Rows[0]["order_amount"].ToString());//订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]  
            biz_content_info.Add("subject", dt.Rows[0]["goods_title"].ToString() + "……");//商品的标题/交易标题/订单标题/订单关键字等。  
            biz_content_info.Add("body", dt.Rows[0]["order_no"].ToString());//对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。  
            biz_content_info.Add("out_trade_no", orderid);//商户网站唯一订单号  
            string strBizContent = JsonConvert.SerializeObject(biz_content_info, timejson);  
            return strBizContent;  
        }  
        /// <summary>  
        /// 组装普通文本请求参数(不带Encode)。  
        /// </summary>  
        /// <param name="parameters">Key-Value形式请求参数字典</param>  
        /// <returns>URL编码后的请求数据</returns>  
        public static string BuildQueryWithOutEncode(IDictionary<string, string> parameters)  
        {  
            StringBuilder postData = new StringBuilder();  
            bool hasParam = false;  

            IEnumerator<KeyValuePair<string, string>> dem = parameters.GetEnumerator();  
            while (dem.MoveNext())  
            {  
                string name = dem.Current.Key;  
                string value = dem.Current.Value;  
                // 忽略参数名或参数值为空的参数  
                if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value))  
                {  
                    if (hasParam)  
                    {  
                        postData.Append("&");  
                    }  

                    postData.Append(name);  
                    postData.Append("=");  

                    string encodedValue = value;  
                    postData.Append(encodedValue);  
                    hasParam = true;  
                }  
            }  
            return postData.ToString();  
        }  

        /// <summary>  
        /// 配置(请自行填上下面两个参数)  注释的部分代码不需要,只需要配置没有注释的4个基础参数  
        /// </summary>  
        public class Config  
        {  
            /// <summary>  
            /// 应用APPID  
            /// </summary>  
            public const string app_id = "自行填写";  
            /// <summary>  
            /// 私钥,通过工具生成 //这个就是生成器里面的那个私钥,第一个大框框那里的.  
            /// </summary>  
            /// rsa_private_key.pem  用于官方SDK获取支付宝支付信息  
            public const string privtekeyNocs8 = "自行填写";  

            //rsa_private_key_pkcs8.pem 用于获取支付宝支付信息  
            public const string privtekey = "自行填写";  

            //string APPID = "2017052207309344";  
            ///// 私钥,通过工具生成 //这个就是生成器里面的那个私钥,第一个大框框那里的.   
            //rsa_private_key.pem 密钥  
            //string APP_PRIVATE_KEY = "自行填写";  
            //rsa_private_key_pkcs8.pem pkcs8密钥  
            //string APP_PRIVATE_KEY = "自行填写";  
            //配置支付宝的公钥 用于异步通知  
            public const string ALIPAY_PUBLIC_KEY = "自行填写";  
            //string CHARSET = "utf-8";  

        }  

        #endregion   

using System;  
using System.Collections.Generic;  
using System.IO;  
using System.Linq;  
using System.Security.Cryptography;  
using System.Text;  

namespace Common.RSAFromPkcs  
{  
    /// <summary>  
    /// 类名:RSAFromPkcs8  
    /// 功能:RSA解密、签名、验签  
    /// 详细:该类对Java生成的密钥进行解密和签名以及验签专用类,不需要修改  
    /// 版本:2.0  
    /// 修改日期:2011-05-10  
    /// 说明:  
    /// 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。  
    /// 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。  
    /// </summary>  
    public sealed class RSAFromPkcs8  
    {  
        /// <summary>  
        /// 签名  
        /// </summary>  
        /// <param name="content">需要签名的内容</param>  
        /// <param name="privateKey">私钥</param>  
        /// <param name="input_charset">编码格式</param>  
        /// <returns></returns>  
        public static string sign(string content, string privateKey, string input_charset)  
        {  
            Encoding code = Encoding.GetEncoding(input_charset);  
            byte[] Data = code.GetBytes(content);  
            RSACryptoServiceProvider rsa = DecodePemPrivateKey(privateKey);  
            SHA1 sh = new SHA1CryptoServiceProvider();  
            byte[] signData = rsa.SignData(Data, sh);  
            return Convert.ToBase64String(signData);  
        }  

        /// <summary>  
        /// 验证签名  
        /// </summary>  
        /// <param name="content">需要验证的内容</param>  
        /// <param name="signedString">签名结果</param>  
        /// <param name="publicKey">公钥</param>  
        /// <param name="input_charset">编码格式</param>  
        /// <returns></returns>  
        public static bool verify(string content, string signedString, string publicKey, string input_charset)  
        {  
            bool result = false;  

            Encoding code = Encoding.GetEncoding(input_charset);  
            byte[] Data = code.GetBytes(content);  
            byte[] data = Convert.FromBase64String(signedString);  
            RSAParameters paraPub = ConvertFromPublicKey(publicKey);  
            RSACryptoServiceProvider rsaPub = new RSACryptoServiceProvider();  
            rsaPub.ImportParameters(paraPub);  

            SHA1 sh = new SHA1CryptoServiceProvider();  
            result = rsaPub.VerifyData(Data, sh, data);  
            return result;  
        }  

        /// <summary>  
        /// 用RSA解密  
        /// </summary>  
        /// <param name="resData">待解密字符串</param>  
        /// <param name="privateKey">私钥</param>  
        /// <param name="input_charset">编码格式</param>  
        /// <returns>解密结果</returns>  
        public static string decryptData(string resData, string privateKey, string input_charset)  
        {  
            byte[] DataToDecrypt = Convert.FromBase64String(resData);  
            List<byte> result = new List<byte>();  

            for (int j = 0; j < DataToDecrypt.Length / 128; j++)  
            {  
                byte[] buf = new byte[128];  
                for (int i = 0; i < 128; i++)  
                {  
                    buf[i] = DataToDecrypt[i + 128 * j];  
                }  
                result.AddRange(decrypt(buf, privateKey, input_charset));  
            }  
            byte[] source = result.ToArray();  
            char[] asciiChars = new char[Encoding.GetEncoding(input_charset).GetCharCount(source, 0, source.Length)];  
            Encoding.GetEncoding(input_charset).GetChars(source, 0, source.Length, asciiChars, 0);  
            return new string(asciiChars);  
        }  

        private static byte[] decrypt(byte[] data, string privateKey, string input_charset)  
        {  
            RSACryptoServiceProvider rsa = DecodePemPrivateKey(privateKey);  
            SHA1 sh = new SHA1CryptoServiceProvider();  
            return rsa.Decrypt(data, false);  
        }  

        /// <summary>  
        /// 解析java生成的pem文件私钥  
        /// </summary>  
        /// <param name="pemstr"></param>  
        /// <returns></returns>  
        private static RSACryptoServiceProvider DecodePemPrivateKey(String pemstr)  
        {  
            byte[] pkcs8privatekey;  
            pkcs8privatekey = Convert.FromBase64String(pemstr);  
            if (pkcs8privatekey != null)  
            {  

                RSACryptoServiceProvider rsa = DecodePrivateKeyInfo(pkcs8privatekey);  
                return rsa;  
            }  
            else  
                return null;  
        }  

        private static RSACryptoServiceProvider DecodePrivateKeyInfo(byte[] pkcs8)  
        {  

            byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };  
            byte[] seq = new byte[15];  

            MemoryStream mem = new MemoryStream(pkcs8);  
            int lenstream = (int)mem.Length;  
            BinaryReader binr = new BinaryReader(mem);    //wrap Memory Stream with BinaryReader for easy reading  
            byte bt = 0;  
            ushort twobytes = 0;  

            try  
            {  

                twobytes = binr.ReadUInt16();  
                if (twobytes == 0x8130)    //data read as little endian order (actual data order for Sequence is 30 81)  
                    binr.ReadByte();    //advance 1 byte  
                else if (twobytes == 0x8230)  
                    binr.ReadInt16();    //advance 2 bytes  
                else  
                    return null;  

                bt = binr.ReadByte();  
                if (bt != 0x02)  
                    return null;  

                twobytes = binr.ReadUInt16();  

                if (twobytes != 0x0001)  
                    return null;  

                seq = binr.ReadBytes(15);        //read the Sequence OID  
                if (!CompareBytearrays(seq, SeqOID))    //make sure Sequence for OID is correct  
                    return null;  

                bt = binr.ReadByte();  
                if (bt != 0x04)    //expect an Octet string   
                    return null;  

                bt = binr.ReadByte();        //read next byte, or next 2 bytes is  0x81 or 0x82; otherwise bt is the byte count  
                if (bt == 0x81)  
                    binr.ReadByte();  
                else  
                    if (bt == 0x82)  
                        binr.ReadUInt16();  
                //------ at this stage, the remaining sequence should be the RSA private key  

                byte[] rsaprivkey = binr.ReadBytes((int)(lenstream - mem.Position));  
                RSACryptoServiceProvider rsacsp = DecodeRSAPrivateKey(rsaprivkey);  
                return rsacsp;  
            }  

            catch (Exception)  
            {  
                return null;  
            }  

            finally { binr.Close(); }  

        }  

        private static bool CompareBytearrays(byte[] a, byte[] b)  
        {  
            if (a.Length != b.Length)  
                return false;  
            int i = 0;  
            foreach (byte c in a)  
            {  
                if (c != b[i])  
                    return false;  
                i++;  
            }  
            return true;  
        }  

        private static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)  
        {  
            byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;  

            // ---------  Set up stream to decode the asn.1 encoded RSA private key  ------  
            MemoryStream mem = new MemoryStream(privkey);  
            BinaryReader binr = new BinaryReader(mem);    //wrap Memory Stream with BinaryReader for easy reading  
            byte bt = 0;  
            ushort twobytes = 0;  
            int elems = 0;  
            try  
            {  
                twobytes = binr.ReadUInt16();  
                if (twobytes == 0x8130)    //data read as little endian order (actual data order for Sequence is 30 81)  
                    binr.ReadByte();    //advance 1 byte  
                else if (twobytes == 0x8230)  
                    binr.ReadInt16();    //advance 2 bytes  
                else  
                    return null;  

                twobytes = binr.ReadUInt16();  
                if (twobytes != 0x0102)    //version number  
                    return null;  
                bt = binr.ReadByte();  
                if (bt != 0x00)  
                    return null;  

                //------  all private key components are Integer sequences ----  
                elems = GetIntegerSize(binr);  
                MODULUS = binr.ReadBytes(elems);  

                elems = GetIntegerSize(binr);  
                E = binr.ReadBytes(elems);  

                elems = GetIntegerSize(binr);  
                D = binr.ReadBytes(elems);  

                elems = GetIntegerSize(binr);  
                P = binr.ReadBytes(elems);  

                elems = GetIntegerSize(binr);  
                Q = binr.ReadBytes(elems);  

                elems = GetIntegerSize(binr);  
                DP = binr.ReadBytes(elems);  

                elems = GetIntegerSize(binr);  
                DQ = binr.ReadBytes(elems);  

                elems = GetIntegerSize(binr);  
                IQ = binr.ReadBytes(elems);  

                // ------- create RSACryptoServiceProvider instance and initialize with public key -----  
                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();  
                RSAParameters RSAparams = new RSAParameters();  
                RSAparams.Modulus = MODULUS;  
                RSAparams.Exponent = E;  
                RSAparams.D = D;  
                RSAparams.P = P;  
                RSAparams.Q = Q;  
                RSAparams.DP = DP;  
                RSAparams.DQ = DQ;  
                RSAparams.InverseQ = IQ;  
                RSA.ImportParameters(RSAparams);  
                return RSA;  
            }  
            catch (Exception)  
            {  
                return null;  
            }  
            finally { binr.Close(); }  
        }  

        private static int GetIntegerSize(BinaryReader binr)  
        {  
            byte bt = 0;  
            byte lowbyte = 0x00;  
            byte highbyte = 0x00;  
            int count = 0;  
            bt = binr.ReadByte();  
            if (bt != 0x02)        //expect integer  
                return 0;  
            bt = binr.ReadByte();  

            if (bt == 0x81)  
                count = binr.ReadByte();    // data size in next byte  
            else  
                if (bt == 0x82)  
                {  
                    highbyte = binr.ReadByte();    // data size in next 2 bytes  
                    lowbyte = binr.ReadByte();  
                    byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };  
                    count = BitConverter.ToInt32(modint, 0);  
                }  
                else  
                {  
                    count = bt;        // we already have the data size  
                }  

            while (binr.ReadByte() == 0x00)  
            {    //remove high order zeros in data  
                count -= 1;  
            }  
            binr.BaseStream.Seek(-1, SeekOrigin.Current);        //last ReadByte wasn't a removed zero, so back up a byte  
            return count;  
        }  

        #region 解析.net 生成的Pem  
        private static RSAParameters ConvertFromPublicKey(string pemFileConent)  
        {  

            byte[] keyData = Convert.FromBase64String(pemFileConent);  
            if (keyData.Length < 162)  
            {  
                throw new ArgumentException("pem file content is incorrect.");  
            }  
            byte[] pemModulus = new byte[128];  
            byte[] pemPublicExponent = new byte[3];  
            Array.Copy(keyData, 29, pemModulus, 0, 128);  
            Array.Copy(keyData, 159, pemPublicExponent, 0, 3);  
            RSAParameters para = new RSAParameters();  
            para.Modulus = pemModulus;  
            para.Exponent = pemPublicExponent;  
            return para;  
        }  

        private static RSAParameters ConvertFromPrivateKey(string pemFileConent)  
        {  
            byte[] keyData = Convert.FromBase64String(pemFileConent);  
            if (keyData.Length < 609)  
            {  
                throw new ArgumentException("pem file content is incorrect.");  
            }  

            int index = 11;  
            byte[] pemModulus = new byte[128];  
            Array.Copy(keyData, index, pemModulus, 0, 128);  

            index += 128;  
            index += 2;//141  
            byte[] pemPublicExponent = new byte[3];  
            Array.Copy(keyData, index, pemPublicExponent, 0, 3);  

            index += 3;  
            index += 4;//148  
            byte[] pemPrivateExponent = new byte[128];  
            Array.Copy(keyData, index, pemPrivateExponent, 0, 128);  

            index += 128;  
            index += ((int)keyData[index + 1] == 64 ? 2 : 3);//279  
            byte[] pemPrime1 = new byte[64];  
            Array.Copy(keyData, index, pemPrime1, 0, 64);  

            index += 64;  
            index += ((int)keyData[index + 1] == 64 ? 2 : 3);//346  
            byte[] pemPrime2 = new byte[64];  
            Array.Copy(keyData, index, pemPrime2, 0, 64);  

            index += 64;  
            index += ((int)keyData[index + 1] == 64 ? 2 : 3);//412/413  
            byte[] pemExponent1 = new byte[64];  
            Array.Copy(keyData, index, pemExponent1, 0, 64);  

            index += 64;  
            index += ((int)keyData[index + 1] == 64 ? 2 : 3);//479/480  
            byte[] pemExponent2 = new byte[64];  
            Array.Copy(keyData, index, pemExponent2, 0, 64);  

            index += 64;  
            index += ((int)keyData[index + 1] == 64 ? 2 : 3);//545/546  
            byte[] pemCoefficient = new byte[64];  
            Array.Copy(keyData, index, pemCoefficient, 0, 64);  

            RSAParameters para = new RSAParameters();  
            para.Modulus = pemModulus;  
            para.Exponent = pemPublicExponent;  
            para.D = pemPrivateExponent;  
            para.P = pemPrime1;  
            para.Q = pemPrime2;  
            para.DP = pemExponent1;  
            para.DQ = pemExponent2;  
            para.InverseQ = pemCoefficient;  
            return para;  
        }  
        #endregion  
    }  
}  

微信支付

 #region 微信支付  

        [HttpPost, Route("OrderPay/GetWxPayInfo")]  
        public string GetWxPayInfo(dynamic obj)  
        {  
            string strJson = string.Empty;  
            try  
            {  
                string orderid = Convert.ToString(obj.orderid);  
                Model.dt_shop_orders orderEntity = new BLL.dt_shop_orders().GetModel(int.Parse(orderid));  
                if (orderEntity != null && orderEntity.id > 0)  
                {  
                    decimal amount = orderEntity.order_amount;  
                    string horderId = orderEntity.id.ToString();  
                    string trade_no = orderEntity.order_no.ToString();  
                    string hopenid = "";  
                    string parameters = WxPayDataGet(amount, horderId, trade_no, hopenid, horderId);  

                    return new  Common.DotNetJson.JSONAPI().ToJson(parameters, "获取微信支付信息成功!", 0);  
                    //JsonConvert.SerializeObject("{\"msg\":\"" + parameters + "\",\"type\":\"wxpay\"}"), "获取微信支付信息成功!", 0);  
                }  
                else  
                {  
                    return new  Common.DotNetJson.JSONAPI().ToJson(JsonConvert.SerializeObject("{\"error\":\"当前订单已失效!\"}"), "获取支付信息失败!", 1);  
                }  
            }  
            catch (Exception ex)  
            {  
                 FileOperate.WriteLogInfo("", "GetPayInfo Exception:" + ex.Message);  
                return new  Common.DotNetJson.JSONAPI().ToJson("{\"error\":\"" + ex.Message + "\"}", "获取微信支付信息失败!", 1);  

            }  

        }  

        /// <summary>  
        /// 微信支付:生成请求数据  
        /// </summary>  
        /// <param name="openid">微信用户id</openid>  
        /// <param name="ttFee">商品总价格</param>  
        /// <param name="busiBody"></param>  
        /// <returns></returns>   
        protected string WxPayDataGet(decimal ttFee, string busiBody, string out_trade_no, string openid, string otid)  
        {  

            //BLL.wx_payment_wxpay wxPayBll = new BLL.wx_payment_wxpay();  
            //Model.wx_payment_wxpay paymentInfo = wxPayBll.GetModelByWid(wid);  

            //先设置基本信息  
            //string partnerId = ""; // paymentInfo.partnerId;// " ";//    
            //string appId = ""; // paymentInfo.appId;// " ";//   
            //string partnerKey = ""; // paymentInfo.partnerKey;// " ";//    
            ////paysignkey(非appkey)    
            //string appKey = ""; // paymentInfo.paySignKey;  
            //--  
            JsApiPay jsApiPay = new JsApiPay();  
            jsApiPay.openid = openid;  
            jsApiPay.total_fee = int.Parse(((int)(ttFee * 100)).ToString());  

            string attch = 3 + "|" + otid + "|我爱我县";  
            WxPayData unifiedOrderResult = jsApiPay.GetUnifiedOrderResult(openid, otid, attch, "woaiwoxian");  

            WxPayData jsApiParam = new WxPayData();  
            string time = WxPayApi.GenerateTimeStamp();  
            string nonceStr = WxPayApi.GenerateNonceStr();  
            string pack = "prepay_id=" + unifiedOrderResult.GetValue("prepay_id");  

            //**************************************************封装调起微信客户端支付界面字符串********************  
            //设置待加密支付参数并加密  
            string appid = unifiedOrderResult.GetValue("appid").ToString();  
            string mch_Id = unifiedOrderResult.GetValue("mch_id").ToString();  
            string prepay_id = unifiedOrderResult.GetValue("prepay_id").ToString();  

            jsApiParam.SetValue("appId", appid); //   
            jsApiParam.SetValue("partnerid", mch_Id);  
            jsApiParam.SetValue("prepayid", prepay_id);  
            jsApiParam.SetValue("package", "Sign=WXPay");  
            jsApiParam.SetValue("nonceStr", nonceStr);  
            jsApiParam.SetValue("timeStamp", time);  
            string sign = jsApiParam.MakeSign();  
            // jsApiParam.SetValue("sign", sign);  

            //设置支付包参数   
            WxPayData paydata = new WxPayData();  
            paydata.SetValue("retcode", 0);//5+固定调起参数  
            paydata.SetValue("retmsg", "ok");//5+固定调起参数  
            paydata.SetValue("appid", appid);//AppId,微信开放平台新建应用时产生  
            paydata.SetValue("partnerid", mch_Id);//商户编号,微信开放平台申请微信支付时产生  
            paydata.SetValue("prepayid", prepay_id);//由上面获取预支付流程获取  
            paydata.SetValue("package", "Sign=WXpay");//APP支付固定设置参数  
            paydata.SetValue("noncestr", nonceStr);//随机字符串,  
            paydata.SetValue("timestamp", time);//时间戳  

            Hashtable paySignReqHandler = new Hashtable();  
            paySignReqHandler.Add("appid", appid);  
            paySignReqHandler.Add("partnerid", mch_Id);  
            paySignReqHandler.Add("prepayid", prepay_id);  
            paySignReqHandler.Add("noncestr", nonceStr);  
            paySignReqHandler.Add("package", "Sign=WXpay");  
            paySignReqHandler.Add("timestamp", time.ToString());  
            var paySign = CreateMd5Sign(paySignReqHandler);   
            paydata.SetValue("sign", paySign);//时间戳  

            //var serializer = new JavaScriptSerializer();  
            //var result = serializer.Serialize(obj);  

            //paySign = HttpUtility.UrlEncode(paySign, Encoding.UTF8);  
            //string payInfo = GetOrderInfoWithEncode() + "&sign=" + sign;  
            //strJson = payInfo.Replace("+", "%20");//日期那里会有一个空格(2017-01-05 11:11:11)转化为+,所以这里要替换一下  
            // FileOperate.WriteLogInfo("", "支付宝串:" + strJson);  

            string result = paydata.ToJson();  

           // FileOperate.WriteLogInfo("", "result:" + result);  
            return result;  

        }  
  private string CreateMd5Sign(Hashtable parameters)  
        {  
            var sb = new StringBuilder();  
            var akeys = new ArrayList(parameters.Keys);  
            akeys.Sort();//排序,这是微信要求的  
            foreach (string k in akeys)  
            {  
                var v = (string)parameters[k];  
                sb.Append(k + "=" + v + "&");  
            }  
            sb.Append("key=" + WxPayAPI.WxPayConfig.KEY);  
            string sign = GetMD5(sb.ToString());  
            return sign;  
        }  
        private string GetMD5(string src)  
        {  
            MD5 md5 = new MD5CryptoServiceProvider();  
            byte[] data = Encoding.UTF8.GetBytes(src);  
            byte[] md5data = md5.ComputeHash(data);  
            md5.Clear();  
            var retStr = BitConverter.ToString(md5data);  
            retStr = retStr.Replace("-", "").ToUpper();  
            return retStr;  
        }  

        #endregion  

  //=========================================================================  
  //微信支付demo里面的部分代码   JsApiPay ,其他的代码基本在微信sdk demo里面基本完成,细节部分自己待处理就好了   

  /**  
         * 调用统一下单,获得下单结果  
         * @return 统一下单结果  
         * @失败时抛异常WxPayException  
         */  
        public WxPayData GetUnifiedOrderResult(string hasopenid, string body, string attach, string tag)  
        {  
            string strSql = string.Format(@"select dt_shop_orders.id,dt_shop_orders.order_no,dt_shop_orders.order_amount,dt_shop_order_goods.goods_title from dt_shop_orders  
                                            left join dt_shop_order_goods on dt_shop_orders.id  = dt_shop_order_goods.order_id where dt_shop_orders.id = {0}", body);  
            DataTable dt = DbHelperSQL.Query(strSql).Tables[0];  
            //统一下单  
            WxPayData data = new WxPayData();  
            data.SetValue("body", dt.Rows[0]["goods_title"].ToString() + "...");  
            data.SetValue("attach", attach);  
            data.SetValue("out_trade_no", body);  
            data.SetValue("total_fee", total_fee);  
            data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));  
            data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));  
            data.SetValue("goods_tag", tag);  
            data.SetValue("trade_type", "APP");  
            data.SetValue("openid", hasopenid);  
            //异步通知url未设置,则使用配置文件中的url   
            data.SetValue("notify_url", "http://异步通知url/OrderPay/WXUpdateStatus");//异步通知url OrderPay/WXUpdateStatus  
            data.SetValue("appid", WxPayConfig.APPID);//公众账号ID  
            data.SetValue("mch_id", WxPayConfig.MCHID);//商户号  
            data.SetValue("spbill_create_ip", WxPayConfig.IP);//终端ip               
            data.SetValue("nonce_str",  WxPayApi.GenerateNonceStr());//随机字符串  

             //签名  
            data.SetValue("sign", data.MakeSign());  

            WxPayData result = WxPayApi.UnifiedOrder(data);  

            if (!result.IsSet("appid") || !result.IsSet("prepay_id") || result.GetValue("prepay_id").ToString() == "")  
            {  
                Log.Error(this.GetType().ToString(), "UnifiedOrder response error!");  
                throw new WxPayException("UnifiedOrder response error!");  
            }  

            unifiedOrderResult = result;  
            return result;  
        }  

支付宝
Android&iOS
错误码 错误描述
8000 正在处理中,支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态
4000 订单支付失败
5000 重复请求
6001 用户中途取消
6002 网络连接出错
6004 支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态
微信支付
Android&iOS
错误码 错误描述
-1 可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等
-2 无需处理。发生场景:用户不支付了,点击取消,返回APP。
-3 发送失败
-4 授权失败
-5 微信不支持

  • 最后说明: 支付宝支付签名是 rsa_private_key_pkcs8 这个方式,千万不搞错了,本文使用是RSA,不是RSA2,然后支付宝 公钥 私钥不要搞错了 ,支付宝支付支持在线调试,微信不支持,需要打包安装才能测试支付功能,
    微信支付还有一个点,密钥需要一致,不能错误!

由于时间匆忙,贴了一些代码,需要各位同学自行完善和修改,如有错误,欢迎指出我来及时修改完善,其他问题, 欢迎加群来咨询交流学习!谢谢大家

继续阅读 »

NET-C#开发HBuillder的APP ,QQ群 :661996236

最近由于连续太多人找我咨询NET_C#开发支付功能,请求协助和demo,所以本人在此简单分享一下,其实在本社区内,已有一部分代码了。

链接:C#配置支付宝信息

APP前端开发调用代码示例,由于是项目部分代码,请自行完善APP前端支付代码,返回测试数据,只是演示,数据自行测试输出,由于
备注 : 获取支付通道

APP端调用代码说明


    //定义支付通道  
    var channel = null;  
    var channelali = null;  
    var channelwx = null;  

    //获取支付通道的方法  
    function getChannels() {  
        plus.payment.getChannels(function (channels) {  
            channelali = channels[0];  
            channelwx = channels[1];  

//          for (var i = 0; i < channels.length; i++) {  
//                 
//              //if(mr=="支付宝")  
//              //{  
//                  if (channels[i].id == "alipay")   
//                  { //wxpay  //alipay  
//                      channelali = channels[i];   
//                  }  
//              //}   
//              //if(mr=="微信")  
//              //{  
//                 if (channels[i].id == "wxpay")  
//                 { //wxpay  //alipay  
//                     channelwx = channels[i];   
//                 }  
//            // }  
//          }  
            // plus.ui.toast("使用支付方式:" + channel.id);  
        }, function (e) {  
            plus.ui.toast("获取支付通道失败!");  
            console.log("获取支付通道失败!");  
        })  
    }  

//支付事件  
 mui('.gouwuche').on('tap', '#waitpay', function (event) {  
        channel = null;  

        var payv = g("pay").value;  
        console.log(payv);  
        if (payv == '2') {  
            urlpay = "OrderPay/GetWxPayInfo";  
            console.log(urlpay);  
        } else {  
            urlpay = "OrderPay/PayMent";  
            console.log(urlpay);  
        }  
        //获取支付通道  
        // getChannels( );  
        // console.log(channel.id);  
        //apiurl + "AliPay/testsign" OrderPay/PayMent   Weixin/GetPayInfo  

        postwait(apiurl + urlpay, returnJson({  
                    orderid: order_no,  
                    type: '3'  
                }), function (data) {  
                    //console.log(data);  
                    var err = JSON.parse(data).err;  
                    if (err == 0) {  
                        var appdata = JSON.parse(data).data;  
                        //console.log(m);  
                        getChannels();  
                        var pay = g("pay").value;  
                        console.log(appdata.msg);  
                        if (pay == 1)   //channel.id== 'alipay')  
                        {  
                            appdata = appdata.msg; //JSON.parse(appdata).msg; //支付宝  
                            channel = channelali;  
                            console.log(channelali.id);  
                        } else {  
                            channel = channelwx;  
                            console.log(channelwx.id);  
                            // console.log("==微信信息=="+ JSON.stringify(appdata));  
                            // appdata = JSON.stringify(appdata); //微信  
                        }  
                        // console.log("==支付信息=="+ appdata);  
                        //appdata='{"appid":"wx123456789,"noncestr":"QtyOdJUspxLGOG5c","package":"Sign=WXPay","partnerid":"12345678","prepayid":"wx20179876543234","timestamp":1496823681,"sign":"DD2D77CE3A770C497A03B3BCEABEF12C"}';  

                        plus.payment.request(channel, appdata, function (result) {  

                                // 弹出系统提示对话框  
                                //mui.toast("支付成功!");   
                                plus.nativeUI.alert( "支付成功!",  
                                 function()  
                                 {   
                                     //修改订单状态   
                                     postwait(apiurl + "OrderPay/UpdateOrderStatus", returnJson({  
                                            orderid: order_no,  
                                            type: 3  
                                        }), function (data) {  
                                            console.log("修改:"+data);  

                                            //openwindows("../../index.html","index.html");   
                                            //alert('22');   
                                            //alert("end");  

                                             var obj = plus.webview.getWebviewById("shopsDetails");  
                                             if(obj!=null){ obj.reload(); }  

                                             plus.webview.getLaunchWebview().evalJS("orderlist();");     
                                                                             plus.webview.getLaunchWebview().show();   

                                            }  
                                        );   
                                  }, "测试支付", "确认" );    

                        }, function (error) {  

                            if (error.code == 62001) {  
                                mui.toast("您放弃支付.");  
                                // mui.back();  
                            } else {  
                                //alert(error.message);  
                                mui.toast("请前往订单管理尝试支付.");   
                                // plus.nativeUI.alert("支付失败", null,  "请前往订单管理尝试支付,支付失败:"+error.code  );   
                            }  
                            var obj = plus.webview.getWebviewById("shopsDetails");  
                            if(obj!=null){ obj.reload(); }  

                             plus.webview.getLaunchWebview().evalJS("orderlist();");     
                             plus.webview.getLaunchWebview().show();   
                        });  

                   //  

                    } else {  
                        var msg = JSON.parse(data).msg;   //JSON.parse(JSON.parse(data).data).error; //JSON.parse(data).msg;  
                        mui.toast(msg);  
                    }  
                }  
        );  

      //跳转   
       var obj = plus.webview.getWebviewById("middle_main.html");  
       if(obj!=null)  
         obj.reload();  

       //plus.webview.currentWebview().close();   
       openwindows("/pages/home/middle_main.html", "middle_main.html", { address_id: 1 });   

    });

NET-C#支付宝代码验证以及生成支付字符串

支付宝支付

支付宝参考:
链接:C#配置支付宝信息

本文使用C# WebAPI方式

  /// <summary>  
        /// 获取支付信息  
        /// </summary>  
        /// <param name="_amount"></param>  
        /// <returns></returns>  
        [HttpPost, Route("Alipay/GetPayInfo")]  
        public string GetPayInfo(string orderid)//_amount:付款金额  
        {  
            string strJson = string.Empty;  
            try  
            {  
                //string _amount = "0.01";  
                string orderInfo = GetOrderInfoWithOutEncode(orderid);  
                // 对订单做RSA 签名  
                string sign = RSAFromPkcs8.sign(orderInfo, Config.privtekey, "utf-8");  
                //仅需对sign做URL编码  
                sign = HttpUtility.UrlEncode(sign, Encoding.UTF8);  
                string payInfo = GetOrderInfoWithEncode() + "&sign=" + sign;  
                strJson = payInfo.Replace("+", "%20");//日期那里会有一个空格(2017-01-05 11:11:11)转化为+,所以这里要替换一下  
                DTcms.Common.FileOperate.WriteLogInfo("", "支付宝串:" + strJson);  
            }  
            catch (Exception ex)  
            {  
                DTcms.Common.FileOperate.WriteLogInfo("", "GetPayInfo Exception:" + ex.Message);  
                //FileLog.WriteLog(ex.ToString());  

            }  
            return strJson;  
        }  

      /// <summary>  
        /// 不包含Encode的字符串拼接  
        /// </summary>  
        /// <param name="price"></param>  
        /// <returns></returns>  
        public string GetOrderInfoWithOutEncode(string orderid)  
        {  
            //  DTcms.Common.FileOperate.WriteLogInfo("", "支付宝串:" + strJson);  

            PayInfo.Add("app_id", Config.app_id);  
            PayInfo.Add("biz_content", GetBizContent(orderid));  
            PayInfo.Add("charset", "utf-8");  
            PayInfo.Add("format", "json");  
            PayInfo.Add("method", "alipay.trade.app.pay");  
            PayInfo.Add("notify_url", "http://www.baidu.com/OrderPay/PayUpdateStatus");  
            PayInfo.Add("sign_type", "RSA");  
            PayInfo.Add("timestamp", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));  
            PayInfo.Add("version", "1.0");  
            string strUrl = BuildQueryWithOutEncode(PayInfo);  
            return strUrl;  
        }  

        /// <summary>  
        /// 获取支付内容详情  
        /// </summary>  
        /// <param name="total_amount"></param>  
        /// <returns></returns>  
        public string GetBizContent(string orderid)  
        {  
            string strSql = string.Format(@"select dt_shop_orders.id,dt_shop_orders.order_no,dt_shop_orders.order_amount,dt_shop_order_goods.goods_title from dt_shop_orders  
                                            left join dt_shop_order_goods on dt_shop_orders.id  = dt_shop_order_goods.order_id where dt_shop_orders.id = {0}", orderid);  
            DataTable dt = DbHelperSQL.Query(strSql).Tables[0];  
            Dictionary<string, string> biz_content_info = new Dictionary<string, string>();  
            biz_content_info.Add("timeout_express", "30m");//该笔订单允许的最晚付款时间,逾期将关闭交易。  
            biz_content_info.Add("seller_id", "");//收款支付宝用户ID。 如果该值为空,则默认为商户签约账号对应的支付宝用户ID  
            biz_content_info.Add("product_code", "QUICK_MSECURITY_PAY");//销售产品码,商家和支付宝签约的产品码,为固定值QUICK_MSECURITY_PAY  
            biz_content_info.Add("total_amount", dt.Rows[0]["order_amount"].ToString());//订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]  
            biz_content_info.Add("subject", dt.Rows[0]["goods_title"].ToString() + "……");//商品的标题/交易标题/订单标题/订单关键字等。  
            biz_content_info.Add("body", dt.Rows[0]["order_no"].ToString());//对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。  
            biz_content_info.Add("out_trade_no", orderid);//商户网站唯一订单号  
            string strBizContent = JsonConvert.SerializeObject(biz_content_info, timejson);  
            return strBizContent;  
        }  
        /// <summary>  
        /// 组装普通文本请求参数(不带Encode)。  
        /// </summary>  
        /// <param name="parameters">Key-Value形式请求参数字典</param>  
        /// <returns>URL编码后的请求数据</returns>  
        public static string BuildQueryWithOutEncode(IDictionary<string, string> parameters)  
        {  
            StringBuilder postData = new StringBuilder();  
            bool hasParam = false;  

            IEnumerator<KeyValuePair<string, string>> dem = parameters.GetEnumerator();  
            while (dem.MoveNext())  
            {  
                string name = dem.Current.Key;  
                string value = dem.Current.Value;  
                // 忽略参数名或参数值为空的参数  
                if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value))  
                {  
                    if (hasParam)  
                    {  
                        postData.Append("&");  
                    }  

                    postData.Append(name);  
                    postData.Append("=");  

                    string encodedValue = value;  
                    postData.Append(encodedValue);  
                    hasParam = true;  
                }  
            }  
            return postData.ToString();  
        }  

        /// <summary>  
        /// 配置(请自行填上下面两个参数)  注释的部分代码不需要,只需要配置没有注释的4个基础参数  
        /// </summary>  
        public class Config  
        {  
            /// <summary>  
            /// 应用APPID  
            /// </summary>  
            public const string app_id = "自行填写";  
            /// <summary>  
            /// 私钥,通过工具生成 //这个就是生成器里面的那个私钥,第一个大框框那里的.  
            /// </summary>  
            /// rsa_private_key.pem  用于官方SDK获取支付宝支付信息  
            public const string privtekeyNocs8 = "自行填写";  

            //rsa_private_key_pkcs8.pem 用于获取支付宝支付信息  
            public const string privtekey = "自行填写";  

            //string APPID = "2017052207309344";  
            ///// 私钥,通过工具生成 //这个就是生成器里面的那个私钥,第一个大框框那里的.   
            //rsa_private_key.pem 密钥  
            //string APP_PRIVATE_KEY = "自行填写";  
            //rsa_private_key_pkcs8.pem pkcs8密钥  
            //string APP_PRIVATE_KEY = "自行填写";  
            //配置支付宝的公钥 用于异步通知  
            public const string ALIPAY_PUBLIC_KEY = "自行填写";  
            //string CHARSET = "utf-8";  

        }  

        #endregion   

using System;  
using System.Collections.Generic;  
using System.IO;  
using System.Linq;  
using System.Security.Cryptography;  
using System.Text;  

namespace Common.RSAFromPkcs  
{  
    /// <summary>  
    /// 类名:RSAFromPkcs8  
    /// 功能:RSA解密、签名、验签  
    /// 详细:该类对Java生成的密钥进行解密和签名以及验签专用类,不需要修改  
    /// 版本:2.0  
    /// 修改日期:2011-05-10  
    /// 说明:  
    /// 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。  
    /// 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。  
    /// </summary>  
    public sealed class RSAFromPkcs8  
    {  
        /// <summary>  
        /// 签名  
        /// </summary>  
        /// <param name="content">需要签名的内容</param>  
        /// <param name="privateKey">私钥</param>  
        /// <param name="input_charset">编码格式</param>  
        /// <returns></returns>  
        public static string sign(string content, string privateKey, string input_charset)  
        {  
            Encoding code = Encoding.GetEncoding(input_charset);  
            byte[] Data = code.GetBytes(content);  
            RSACryptoServiceProvider rsa = DecodePemPrivateKey(privateKey);  
            SHA1 sh = new SHA1CryptoServiceProvider();  
            byte[] signData = rsa.SignData(Data, sh);  
            return Convert.ToBase64String(signData);  
        }  

        /// <summary>  
        /// 验证签名  
        /// </summary>  
        /// <param name="content">需要验证的内容</param>  
        /// <param name="signedString">签名结果</param>  
        /// <param name="publicKey">公钥</param>  
        /// <param name="input_charset">编码格式</param>  
        /// <returns></returns>  
        public static bool verify(string content, string signedString, string publicKey, string input_charset)  
        {  
            bool result = false;  

            Encoding code = Encoding.GetEncoding(input_charset);  
            byte[] Data = code.GetBytes(content);  
            byte[] data = Convert.FromBase64String(signedString);  
            RSAParameters paraPub = ConvertFromPublicKey(publicKey);  
            RSACryptoServiceProvider rsaPub = new RSACryptoServiceProvider();  
            rsaPub.ImportParameters(paraPub);  

            SHA1 sh = new SHA1CryptoServiceProvider();  
            result = rsaPub.VerifyData(Data, sh, data);  
            return result;  
        }  

        /// <summary>  
        /// 用RSA解密  
        /// </summary>  
        /// <param name="resData">待解密字符串</param>  
        /// <param name="privateKey">私钥</param>  
        /// <param name="input_charset">编码格式</param>  
        /// <returns>解密结果</returns>  
        public static string decryptData(string resData, string privateKey, string input_charset)  
        {  
            byte[] DataToDecrypt = Convert.FromBase64String(resData);  
            List<byte> result = new List<byte>();  

            for (int j = 0; j < DataToDecrypt.Length / 128; j++)  
            {  
                byte[] buf = new byte[128];  
                for (int i = 0; i < 128; i++)  
                {  
                    buf[i] = DataToDecrypt[i + 128 * j];  
                }  
                result.AddRange(decrypt(buf, privateKey, input_charset));  
            }  
            byte[] source = result.ToArray();  
            char[] asciiChars = new char[Encoding.GetEncoding(input_charset).GetCharCount(source, 0, source.Length)];  
            Encoding.GetEncoding(input_charset).GetChars(source, 0, source.Length, asciiChars, 0);  
            return new string(asciiChars);  
        }  

        private static byte[] decrypt(byte[] data, string privateKey, string input_charset)  
        {  
            RSACryptoServiceProvider rsa = DecodePemPrivateKey(privateKey);  
            SHA1 sh = new SHA1CryptoServiceProvider();  
            return rsa.Decrypt(data, false);  
        }  

        /// <summary>  
        /// 解析java生成的pem文件私钥  
        /// </summary>  
        /// <param name="pemstr"></param>  
        /// <returns></returns>  
        private static RSACryptoServiceProvider DecodePemPrivateKey(String pemstr)  
        {  
            byte[] pkcs8privatekey;  
            pkcs8privatekey = Convert.FromBase64String(pemstr);  
            if (pkcs8privatekey != null)  
            {  

                RSACryptoServiceProvider rsa = DecodePrivateKeyInfo(pkcs8privatekey);  
                return rsa;  
            }  
            else  
                return null;  
        }  

        private static RSACryptoServiceProvider DecodePrivateKeyInfo(byte[] pkcs8)  
        {  

            byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };  
            byte[] seq = new byte[15];  

            MemoryStream mem = new MemoryStream(pkcs8);  
            int lenstream = (int)mem.Length;  
            BinaryReader binr = new BinaryReader(mem);    //wrap Memory Stream with BinaryReader for easy reading  
            byte bt = 0;  
            ushort twobytes = 0;  

            try  
            {  

                twobytes = binr.ReadUInt16();  
                if (twobytes == 0x8130)    //data read as little endian order (actual data order for Sequence is 30 81)  
                    binr.ReadByte();    //advance 1 byte  
                else if (twobytes == 0x8230)  
                    binr.ReadInt16();    //advance 2 bytes  
                else  
                    return null;  

                bt = binr.ReadByte();  
                if (bt != 0x02)  
                    return null;  

                twobytes = binr.ReadUInt16();  

                if (twobytes != 0x0001)  
                    return null;  

                seq = binr.ReadBytes(15);        //read the Sequence OID  
                if (!CompareBytearrays(seq, SeqOID))    //make sure Sequence for OID is correct  
                    return null;  

                bt = binr.ReadByte();  
                if (bt != 0x04)    //expect an Octet string   
                    return null;  

                bt = binr.ReadByte();        //read next byte, or next 2 bytes is  0x81 or 0x82; otherwise bt is the byte count  
                if (bt == 0x81)  
                    binr.ReadByte();  
                else  
                    if (bt == 0x82)  
                        binr.ReadUInt16();  
                //------ at this stage, the remaining sequence should be the RSA private key  

                byte[] rsaprivkey = binr.ReadBytes((int)(lenstream - mem.Position));  
                RSACryptoServiceProvider rsacsp = DecodeRSAPrivateKey(rsaprivkey);  
                return rsacsp;  
            }  

            catch (Exception)  
            {  
                return null;  
            }  

            finally { binr.Close(); }  

        }  

        private static bool CompareBytearrays(byte[] a, byte[] b)  
        {  
            if (a.Length != b.Length)  
                return false;  
            int i = 0;  
            foreach (byte c in a)  
            {  
                if (c != b[i])  
                    return false;  
                i++;  
            }  
            return true;  
        }  

        private static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)  
        {  
            byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;  

            // ---------  Set up stream to decode the asn.1 encoded RSA private key  ------  
            MemoryStream mem = new MemoryStream(privkey);  
            BinaryReader binr = new BinaryReader(mem);    //wrap Memory Stream with BinaryReader for easy reading  
            byte bt = 0;  
            ushort twobytes = 0;  
            int elems = 0;  
            try  
            {  
                twobytes = binr.ReadUInt16();  
                if (twobytes == 0x8130)    //data read as little endian order (actual data order for Sequence is 30 81)  
                    binr.ReadByte();    //advance 1 byte  
                else if (twobytes == 0x8230)  
                    binr.ReadInt16();    //advance 2 bytes  
                else  
                    return null;  

                twobytes = binr.ReadUInt16();  
                if (twobytes != 0x0102)    //version number  
                    return null;  
                bt = binr.ReadByte();  
                if (bt != 0x00)  
                    return null;  

                //------  all private key components are Integer sequences ----  
                elems = GetIntegerSize(binr);  
                MODULUS = binr.ReadBytes(elems);  

                elems = GetIntegerSize(binr);  
                E = binr.ReadBytes(elems);  

                elems = GetIntegerSize(binr);  
                D = binr.ReadBytes(elems);  

                elems = GetIntegerSize(binr);  
                P = binr.ReadBytes(elems);  

                elems = GetIntegerSize(binr);  
                Q = binr.ReadBytes(elems);  

                elems = GetIntegerSize(binr);  
                DP = binr.ReadBytes(elems);  

                elems = GetIntegerSize(binr);  
                DQ = binr.ReadBytes(elems);  

                elems = GetIntegerSize(binr);  
                IQ = binr.ReadBytes(elems);  

                // ------- create RSACryptoServiceProvider instance and initialize with public key -----  
                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();  
                RSAParameters RSAparams = new RSAParameters();  
                RSAparams.Modulus = MODULUS;  
                RSAparams.Exponent = E;  
                RSAparams.D = D;  
                RSAparams.P = P;  
                RSAparams.Q = Q;  
                RSAparams.DP = DP;  
                RSAparams.DQ = DQ;  
                RSAparams.InverseQ = IQ;  
                RSA.ImportParameters(RSAparams);  
                return RSA;  
            }  
            catch (Exception)  
            {  
                return null;  
            }  
            finally { binr.Close(); }  
        }  

        private static int GetIntegerSize(BinaryReader binr)  
        {  
            byte bt = 0;  
            byte lowbyte = 0x00;  
            byte highbyte = 0x00;  
            int count = 0;  
            bt = binr.ReadByte();  
            if (bt != 0x02)        //expect integer  
                return 0;  
            bt = binr.ReadByte();  

            if (bt == 0x81)  
                count = binr.ReadByte();    // data size in next byte  
            else  
                if (bt == 0x82)  
                {  
                    highbyte = binr.ReadByte();    // data size in next 2 bytes  
                    lowbyte = binr.ReadByte();  
                    byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };  
                    count = BitConverter.ToInt32(modint, 0);  
                }  
                else  
                {  
                    count = bt;        // we already have the data size  
                }  

            while (binr.ReadByte() == 0x00)  
            {    //remove high order zeros in data  
                count -= 1;  
            }  
            binr.BaseStream.Seek(-1, SeekOrigin.Current);        //last ReadByte wasn't a removed zero, so back up a byte  
            return count;  
        }  

        #region 解析.net 生成的Pem  
        private static RSAParameters ConvertFromPublicKey(string pemFileConent)  
        {  

            byte[] keyData = Convert.FromBase64String(pemFileConent);  
            if (keyData.Length < 162)  
            {  
                throw new ArgumentException("pem file content is incorrect.");  
            }  
            byte[] pemModulus = new byte[128];  
            byte[] pemPublicExponent = new byte[3];  
            Array.Copy(keyData, 29, pemModulus, 0, 128);  
            Array.Copy(keyData, 159, pemPublicExponent, 0, 3);  
            RSAParameters para = new RSAParameters();  
            para.Modulus = pemModulus;  
            para.Exponent = pemPublicExponent;  
            return para;  
        }  

        private static RSAParameters ConvertFromPrivateKey(string pemFileConent)  
        {  
            byte[] keyData = Convert.FromBase64String(pemFileConent);  
            if (keyData.Length < 609)  
            {  
                throw new ArgumentException("pem file content is incorrect.");  
            }  

            int index = 11;  
            byte[] pemModulus = new byte[128];  
            Array.Copy(keyData, index, pemModulus, 0, 128);  

            index += 128;  
            index += 2;//141  
            byte[] pemPublicExponent = new byte[3];  
            Array.Copy(keyData, index, pemPublicExponent, 0, 3);  

            index += 3;  
            index += 4;//148  
            byte[] pemPrivateExponent = new byte[128];  
            Array.Copy(keyData, index, pemPrivateExponent, 0, 128);  

            index += 128;  
            index += ((int)keyData[index + 1] == 64 ? 2 : 3);//279  
            byte[] pemPrime1 = new byte[64];  
            Array.Copy(keyData, index, pemPrime1, 0, 64);  

            index += 64;  
            index += ((int)keyData[index + 1] == 64 ? 2 : 3);//346  
            byte[] pemPrime2 = new byte[64];  
            Array.Copy(keyData, index, pemPrime2, 0, 64);  

            index += 64;  
            index += ((int)keyData[index + 1] == 64 ? 2 : 3);//412/413  
            byte[] pemExponent1 = new byte[64];  
            Array.Copy(keyData, index, pemExponent1, 0, 64);  

            index += 64;  
            index += ((int)keyData[index + 1] == 64 ? 2 : 3);//479/480  
            byte[] pemExponent2 = new byte[64];  
            Array.Copy(keyData, index, pemExponent2, 0, 64);  

            index += 64;  
            index += ((int)keyData[index + 1] == 64 ? 2 : 3);//545/546  
            byte[] pemCoefficient = new byte[64];  
            Array.Copy(keyData, index, pemCoefficient, 0, 64);  

            RSAParameters para = new RSAParameters();  
            para.Modulus = pemModulus;  
            para.Exponent = pemPublicExponent;  
            para.D = pemPrivateExponent;  
            para.P = pemPrime1;  
            para.Q = pemPrime2;  
            para.DP = pemExponent1;  
            para.DQ = pemExponent2;  
            para.InverseQ = pemCoefficient;  
            return para;  
        }  
        #endregion  
    }  
}  

微信支付

 #region 微信支付  

        [HttpPost, Route("OrderPay/GetWxPayInfo")]  
        public string GetWxPayInfo(dynamic obj)  
        {  
            string strJson = string.Empty;  
            try  
            {  
                string orderid = Convert.ToString(obj.orderid);  
                Model.dt_shop_orders orderEntity = new BLL.dt_shop_orders().GetModel(int.Parse(orderid));  
                if (orderEntity != null && orderEntity.id > 0)  
                {  
                    decimal amount = orderEntity.order_amount;  
                    string horderId = orderEntity.id.ToString();  
                    string trade_no = orderEntity.order_no.ToString();  
                    string hopenid = "";  
                    string parameters = WxPayDataGet(amount, horderId, trade_no, hopenid, horderId);  

                    return new  Common.DotNetJson.JSONAPI().ToJson(parameters, "获取微信支付信息成功!", 0);  
                    //JsonConvert.SerializeObject("{\"msg\":\"" + parameters + "\",\"type\":\"wxpay\"}"), "获取微信支付信息成功!", 0);  
                }  
                else  
                {  
                    return new  Common.DotNetJson.JSONAPI().ToJson(JsonConvert.SerializeObject("{\"error\":\"当前订单已失效!\"}"), "获取支付信息失败!", 1);  
                }  
            }  
            catch (Exception ex)  
            {  
                 FileOperate.WriteLogInfo("", "GetPayInfo Exception:" + ex.Message);  
                return new  Common.DotNetJson.JSONAPI().ToJson("{\"error\":\"" + ex.Message + "\"}", "获取微信支付信息失败!", 1);  

            }  

        }  

        /// <summary>  
        /// 微信支付:生成请求数据  
        /// </summary>  
        /// <param name="openid">微信用户id</openid>  
        /// <param name="ttFee">商品总价格</param>  
        /// <param name="busiBody"></param>  
        /// <returns></returns>   
        protected string WxPayDataGet(decimal ttFee, string busiBody, string out_trade_no, string openid, string otid)  
        {  

            //BLL.wx_payment_wxpay wxPayBll = new BLL.wx_payment_wxpay();  
            //Model.wx_payment_wxpay paymentInfo = wxPayBll.GetModelByWid(wid);  

            //先设置基本信息  
            //string partnerId = ""; // paymentInfo.partnerId;// " ";//    
            //string appId = ""; // paymentInfo.appId;// " ";//   
            //string partnerKey = ""; // paymentInfo.partnerKey;// " ";//    
            ////paysignkey(非appkey)    
            //string appKey = ""; // paymentInfo.paySignKey;  
            //--  
            JsApiPay jsApiPay = new JsApiPay();  
            jsApiPay.openid = openid;  
            jsApiPay.total_fee = int.Parse(((int)(ttFee * 100)).ToString());  

            string attch = 3 + "|" + otid + "|我爱我县";  
            WxPayData unifiedOrderResult = jsApiPay.GetUnifiedOrderResult(openid, otid, attch, "woaiwoxian");  

            WxPayData jsApiParam = new WxPayData();  
            string time = WxPayApi.GenerateTimeStamp();  
            string nonceStr = WxPayApi.GenerateNonceStr();  
            string pack = "prepay_id=" + unifiedOrderResult.GetValue("prepay_id");  

            //**************************************************封装调起微信客户端支付界面字符串********************  
            //设置待加密支付参数并加密  
            string appid = unifiedOrderResult.GetValue("appid").ToString();  
            string mch_Id = unifiedOrderResult.GetValue("mch_id").ToString();  
            string prepay_id = unifiedOrderResult.GetValue("prepay_id").ToString();  

            jsApiParam.SetValue("appId", appid); //   
            jsApiParam.SetValue("partnerid", mch_Id);  
            jsApiParam.SetValue("prepayid", prepay_id);  
            jsApiParam.SetValue("package", "Sign=WXPay");  
            jsApiParam.SetValue("nonceStr", nonceStr);  
            jsApiParam.SetValue("timeStamp", time);  
            string sign = jsApiParam.MakeSign();  
            // jsApiParam.SetValue("sign", sign);  

            //设置支付包参数   
            WxPayData paydata = new WxPayData();  
            paydata.SetValue("retcode", 0);//5+固定调起参数  
            paydata.SetValue("retmsg", "ok");//5+固定调起参数  
            paydata.SetValue("appid", appid);//AppId,微信开放平台新建应用时产生  
            paydata.SetValue("partnerid", mch_Id);//商户编号,微信开放平台申请微信支付时产生  
            paydata.SetValue("prepayid", prepay_id);//由上面获取预支付流程获取  
            paydata.SetValue("package", "Sign=WXpay");//APP支付固定设置参数  
            paydata.SetValue("noncestr", nonceStr);//随机字符串,  
            paydata.SetValue("timestamp", time);//时间戳  

            Hashtable paySignReqHandler = new Hashtable();  
            paySignReqHandler.Add("appid", appid);  
            paySignReqHandler.Add("partnerid", mch_Id);  
            paySignReqHandler.Add("prepayid", prepay_id);  
            paySignReqHandler.Add("noncestr", nonceStr);  
            paySignReqHandler.Add("package", "Sign=WXpay");  
            paySignReqHandler.Add("timestamp", time.ToString());  
            var paySign = CreateMd5Sign(paySignReqHandler);   
            paydata.SetValue("sign", paySign);//时间戳  

            //var serializer = new JavaScriptSerializer();  
            //var result = serializer.Serialize(obj);  

            //paySign = HttpUtility.UrlEncode(paySign, Encoding.UTF8);  
            //string payInfo = GetOrderInfoWithEncode() + "&sign=" + sign;  
            //strJson = payInfo.Replace("+", "%20");//日期那里会有一个空格(2017-01-05 11:11:11)转化为+,所以这里要替换一下  
            // FileOperate.WriteLogInfo("", "支付宝串:" + strJson);  

            string result = paydata.ToJson();  

           // FileOperate.WriteLogInfo("", "result:" + result);  
            return result;  

        }  
  private string CreateMd5Sign(Hashtable parameters)  
        {  
            var sb = new StringBuilder();  
            var akeys = new ArrayList(parameters.Keys);  
            akeys.Sort();//排序,这是微信要求的  
            foreach (string k in akeys)  
            {  
                var v = (string)parameters[k];  
                sb.Append(k + "=" + v + "&");  
            }  
            sb.Append("key=" + WxPayAPI.WxPayConfig.KEY);  
            string sign = GetMD5(sb.ToString());  
            return sign;  
        }  
        private string GetMD5(string src)  
        {  
            MD5 md5 = new MD5CryptoServiceProvider();  
            byte[] data = Encoding.UTF8.GetBytes(src);  
            byte[] md5data = md5.ComputeHash(data);  
            md5.Clear();  
            var retStr = BitConverter.ToString(md5data);  
            retStr = retStr.Replace("-", "").ToUpper();  
            return retStr;  
        }  

        #endregion  

  //=========================================================================  
  //微信支付demo里面的部分代码   JsApiPay ,其他的代码基本在微信sdk demo里面基本完成,细节部分自己待处理就好了   

  /**  
         * 调用统一下单,获得下单结果  
         * @return 统一下单结果  
         * @失败时抛异常WxPayException  
         */  
        public WxPayData GetUnifiedOrderResult(string hasopenid, string body, string attach, string tag)  
        {  
            string strSql = string.Format(@"select dt_shop_orders.id,dt_shop_orders.order_no,dt_shop_orders.order_amount,dt_shop_order_goods.goods_title from dt_shop_orders  
                                            left join dt_shop_order_goods on dt_shop_orders.id  = dt_shop_order_goods.order_id where dt_shop_orders.id = {0}", body);  
            DataTable dt = DbHelperSQL.Query(strSql).Tables[0];  
            //统一下单  
            WxPayData data = new WxPayData();  
            data.SetValue("body", dt.Rows[0]["goods_title"].ToString() + "...");  
            data.SetValue("attach", attach);  
            data.SetValue("out_trade_no", body);  
            data.SetValue("total_fee", total_fee);  
            data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));  
            data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));  
            data.SetValue("goods_tag", tag);  
            data.SetValue("trade_type", "APP");  
            data.SetValue("openid", hasopenid);  
            //异步通知url未设置,则使用配置文件中的url   
            data.SetValue("notify_url", "http://异步通知url/OrderPay/WXUpdateStatus");//异步通知url OrderPay/WXUpdateStatus  
            data.SetValue("appid", WxPayConfig.APPID);//公众账号ID  
            data.SetValue("mch_id", WxPayConfig.MCHID);//商户号  
            data.SetValue("spbill_create_ip", WxPayConfig.IP);//终端ip               
            data.SetValue("nonce_str",  WxPayApi.GenerateNonceStr());//随机字符串  

             //签名  
            data.SetValue("sign", data.MakeSign());  

            WxPayData result = WxPayApi.UnifiedOrder(data);  

            if (!result.IsSet("appid") || !result.IsSet("prepay_id") || result.GetValue("prepay_id").ToString() == "")  
            {  
                Log.Error(this.GetType().ToString(), "UnifiedOrder response error!");  
                throw new WxPayException("UnifiedOrder response error!");  
            }  

            unifiedOrderResult = result;  
            return result;  
        }  

支付宝
Android&iOS
错误码 错误描述
8000 正在处理中,支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态
4000 订单支付失败
5000 重复请求
6001 用户中途取消
6002 网络连接出错
6004 支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态
微信支付
Android&iOS
错误码 错误描述
-1 可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等
-2 无需处理。发生场景:用户不支付了,点击取消,返回APP。
-3 发送失败
-4 授权失败
-5 微信不支持

  • 最后说明: 支付宝支付签名是 rsa_private_key_pkcs8 这个方式,千万不搞错了,本文使用是RSA,不是RSA2,然后支付宝 公钥 私钥不要搞错了 ,支付宝支付支持在线调试,微信不支持,需要打包安装才能测试支付功能,
    微信支付还有一个点,密钥需要一致,不能错误!

由于时间匆忙,贴了一些代码,需要各位同学自行完善和修改,如有错误,欢迎指出我来及时修改完善,其他问题, 欢迎加群来咨询交流学习!谢谢大家

收起阅读 »

plus.maps.Map("xxx").getUserLocation VS plus.geolocation.getCurrentPosition

项目中一开始混用了

getUserLocation

getCurrentPosition

###############
官方文档写的很不透彻,我在开发的过程中也是用的模棱两可。
写这篇文章是自己开发过程的一个记录,也是功能迭代优化的不断尝试。
希望最终能把他两说清楚。
###############

前提是配置好地图SDK需要的appkey;

混用的原因是:

  1. 不但需要准确的地理坐标,还需要具体省市区街道信息
  2. getUserLocation得到的坐标经过reverseGeocode反向地理编码拿到的address是String,信息量很少
  3. getCurrentPosition得到的address直接就是Object:country、province、city、district、street、poiName、cityCode。

    这种数据用起来更方便。

    同时还有String格式的addresses属性,基本可以理解为address对象中地址属性串联,但也不是机械的串联,中间存在有语意的形容词。

  4. 真机调试时getCurrentPosition取到的地理坐标偏差非常大,2km的级别。而getUserLocation相对比较准确。

这里有个大坑
getCurrentPosition优先使用的定位模块:amap>baidu>system,来自HTML5 官方文档
真机调试默认baidu地图,baidu地图默认bd09ll坐标系,而getCurrentPosition不设置参数的话默认amap是gcj02坐标系!!!
偏差不大就见鬼了!没有偏差gcj02岂不是搞了个国际笑话!
有偏差才正常!
HBuilder这个默认不一致的坑把我坑坏了

最后做性能和代码优化的时候,觉得这种做法有问题,不够优雅!就仔细研究了他两的区别。

总结如下:

  1. 真机调试虽然是通过手机启动服务,但是实际上使用的是HBuilder默认的配置
  2. 默认使用的地图provider是baidu,并且getUserLocation和reverseGeocode方法的coordType默认是bd09ll。
    并且是不可以修改的!想用amap调试,只能一遍一遍的打包安装!
  3. getCurrentPosition定位实际上是通过GPS定位,缺点是如果在室内使用4G网络,定位非常不准,使用WiFi比较准。
    如果室外4G GPS的精度是最高的。这里要吐槽下,baidu的准确度木有amap高。
  4. 从HTML5 官方文档看,getCurrentPosition通过手机GPS设备或其它信息如IP地址、移动网络信号获取。具体优先级策略不详。
    getUserLocation只有一句:获取用户当前位置信息将打开定位设备。
    getCurrentPosition默认采用amap,是gcj02坐标系,getUserLocation采用baidu的bd09ll坐标系。

通过测试发现:

  • 如果要使用getCurrentPosition,不论sdk是baidu还是amap,一定要注意设置对应的provider和coordsType。
  • 4G网络下,getCurrentPosition一定优先通过GPS定位,如果在室内就误差很大,定位非常不准。
  • 室内使用WiFi相比4G而言要准一些
  • WIFI就是IP地址或基站定位,准确度完全依赖于数据量,即调用得越多越准确。
  • getUserLocation应该是基于GPS定位,没有验证出来会不会使用基站。关键缺点是能获取到的信息量太少。
  • 我最终采用了getCurrentPosition来确定当前位置,毕竟getCurrentPosition可以自由切换定位方式,其次现在wifi覆盖率非常高,基于位置的服务越来越多,用的人越来越多,基站定位可靠度也会越来越高。

补充:

  1. 坐标转换为什么不用convertCoordinates?
    因为只有百度地图支持这个方法,我不希望被绑架。

后续测试有新发现了继续补充。

继续阅读 »

项目中一开始混用了

getUserLocation

getCurrentPosition

###############
官方文档写的很不透彻,我在开发的过程中也是用的模棱两可。
写这篇文章是自己开发过程的一个记录,也是功能迭代优化的不断尝试。
希望最终能把他两说清楚。
###############

前提是配置好地图SDK需要的appkey;

混用的原因是:

  1. 不但需要准确的地理坐标,还需要具体省市区街道信息
  2. getUserLocation得到的坐标经过reverseGeocode反向地理编码拿到的address是String,信息量很少
  3. getCurrentPosition得到的address直接就是Object:country、province、city、district、street、poiName、cityCode。

    这种数据用起来更方便。

    同时还有String格式的addresses属性,基本可以理解为address对象中地址属性串联,但也不是机械的串联,中间存在有语意的形容词。

  4. 真机调试时getCurrentPosition取到的地理坐标偏差非常大,2km的级别。而getUserLocation相对比较准确。

这里有个大坑
getCurrentPosition优先使用的定位模块:amap>baidu>system,来自HTML5 官方文档
真机调试默认baidu地图,baidu地图默认bd09ll坐标系,而getCurrentPosition不设置参数的话默认amap是gcj02坐标系!!!
偏差不大就见鬼了!没有偏差gcj02岂不是搞了个国际笑话!
有偏差才正常!
HBuilder这个默认不一致的坑把我坑坏了

最后做性能和代码优化的时候,觉得这种做法有问题,不够优雅!就仔细研究了他两的区别。

总结如下:

  1. 真机调试虽然是通过手机启动服务,但是实际上使用的是HBuilder默认的配置
  2. 默认使用的地图provider是baidu,并且getUserLocation和reverseGeocode方法的coordType默认是bd09ll。
    并且是不可以修改的!想用amap调试,只能一遍一遍的打包安装!
  3. getCurrentPosition定位实际上是通过GPS定位,缺点是如果在室内使用4G网络,定位非常不准,使用WiFi比较准。
    如果室外4G GPS的精度是最高的。这里要吐槽下,baidu的准确度木有amap高。
  4. 从HTML5 官方文档看,getCurrentPosition通过手机GPS设备或其它信息如IP地址、移动网络信号获取。具体优先级策略不详。
    getUserLocation只有一句:获取用户当前位置信息将打开定位设备。
    getCurrentPosition默认采用amap,是gcj02坐标系,getUserLocation采用baidu的bd09ll坐标系。

通过测试发现:

  • 如果要使用getCurrentPosition,不论sdk是baidu还是amap,一定要注意设置对应的provider和coordsType。
  • 4G网络下,getCurrentPosition一定优先通过GPS定位,如果在室内就误差很大,定位非常不准。
  • 室内使用WiFi相比4G而言要准一些
  • WIFI就是IP地址或基站定位,准确度完全依赖于数据量,即调用得越多越准确。
  • getUserLocation应该是基于GPS定位,没有验证出来会不会使用基站。关键缺点是能获取到的信息量太少。
  • 我最终采用了getCurrentPosition来确定当前位置,毕竟getCurrentPosition可以自由切换定位方式,其次现在wifi覆盖率非常高,基于位置的服务越来越多,用的人越来越多,基站定位可靠度也会越来越高。

补充:

  1. 坐标转换为什么不用convertCoordinates?
    因为只有百度地图支持这个方法,我不希望被绑架。

后续测试有新发现了继续补充。

收起阅读 »

诚接App开发,可能是目前国内唯一一家能提供完整技术支撑服务的公司

Vue 移动APP 外包

默客科技 (http://www.mokekeji.com) 专业跨平台App开发,提供完整技术支撑服务。

之所以说可能是唯一一家,是因为国内确实没看见其他公司有类似的服务,如果有类似的,望在下方回帖告悉,我看到后就会修改标题。

什么叫做技术支撑?放两张截图就一目了然:


仿github的issue tracker系统,真正快速有效的解决问题。


得益于架构的跨平台版本管理和部署系统,测试或发布都可以一键操作,一目了然。

外包的项目在上线后,会面临大量的问题,比如如何快速修正bug,如何升级迭代,如何进行测试和发布等等。
传统的做法无非是通过各种交流工具催来催去,直到某一方筋疲力尽,然后项目要么停滞,要么重构,我们已经见过无数的案例。

所谓技术支撑,必须有能力替代自身的开发团队。

技术架构

大约一个月前我们在这里发了一篇文章,介绍技术架构和和平台选择的原因 (https://ask.dcloud.net.cn/article/12567),帖子下获得了dcloud官方人员的一些见解,因为话题比较大,所以没有直接回复,这里简述下个人看法。

随着移动设备性能的逐渐提升,原生应用和混合式应用的性能差距将越来越小,所以性能上的考量不再讨论,但是RN或Weex与h5应用间有一个巨大的不同,h5的开发架构过于松散了,它没有强制的开发规范和架构约束。诚然你可以使用react或者vue来开发应用,但Jq仍然在前端领域占绝对优势,现在的大多数前端开发人员可能直到离开这个行业都只会Jq。就像ie一样,除非所有的网站都不再支持ie,否则ie仍然会长期存在下去。

Jq并不是不好,但Jq与mvvm框架对于应用开发的理解方式是完全不同的,这种不同会在项目的可维护性上体现出巨大的差距,一个写Jq五年的工程师可能没有一个写Vue一年的工程师来的bug更少,代码思路更清晰,更容易维护,君不见Github上有许多star非常高的Jq插件仍然是bug满天飞。

强规范架构非常重要,我们始终在贯彻这点。

开发中很常见的一件事,为了实现一个小功能,找了无数插件,终于选定一个后,项目迭代更新,原来的插件不够用了,又要继续找下去。
一个项目会用到很多插件,这些插件很可能没有完整的文档,没有统一的api,这又再次增加了维护的难度。

所以我们专门维护了一套组件库,其中多数是自己开发,少数是封装一些广受认可的组件,然后在项目中特定的功能强制要求使用特定组件的来实现,包括所有页面布局,div + css在这里已经被淘汰。当功能需求变更时,只需要升级对应的组件即可。只有这样才能让开发人员将精力放到业务逻辑上,而不是在一些旁枝末节的地方。

我们致力于开发高质量的跨平台应用,业务联系请参考官网。
http://www.mokekeji.com

继续阅读 »

默客科技 (http://www.mokekeji.com) 专业跨平台App开发,提供完整技术支撑服务。

之所以说可能是唯一一家,是因为国内确实没看见其他公司有类似的服务,如果有类似的,望在下方回帖告悉,我看到后就会修改标题。

什么叫做技术支撑?放两张截图就一目了然:


仿github的issue tracker系统,真正快速有效的解决问题。


得益于架构的跨平台版本管理和部署系统,测试或发布都可以一键操作,一目了然。

外包的项目在上线后,会面临大量的问题,比如如何快速修正bug,如何升级迭代,如何进行测试和发布等等。
传统的做法无非是通过各种交流工具催来催去,直到某一方筋疲力尽,然后项目要么停滞,要么重构,我们已经见过无数的案例。

所谓技术支撑,必须有能力替代自身的开发团队。

技术架构

大约一个月前我们在这里发了一篇文章,介绍技术架构和和平台选择的原因 (https://ask.dcloud.net.cn/article/12567),帖子下获得了dcloud官方人员的一些见解,因为话题比较大,所以没有直接回复,这里简述下个人看法。

随着移动设备性能的逐渐提升,原生应用和混合式应用的性能差距将越来越小,所以性能上的考量不再讨论,但是RN或Weex与h5应用间有一个巨大的不同,h5的开发架构过于松散了,它没有强制的开发规范和架构约束。诚然你可以使用react或者vue来开发应用,但Jq仍然在前端领域占绝对优势,现在的大多数前端开发人员可能直到离开这个行业都只会Jq。就像ie一样,除非所有的网站都不再支持ie,否则ie仍然会长期存在下去。

Jq并不是不好,但Jq与mvvm框架对于应用开发的理解方式是完全不同的,这种不同会在项目的可维护性上体现出巨大的差距,一个写Jq五年的工程师可能没有一个写Vue一年的工程师来的bug更少,代码思路更清晰,更容易维护,君不见Github上有许多star非常高的Jq插件仍然是bug满天飞。

强规范架构非常重要,我们始终在贯彻这点。

开发中很常见的一件事,为了实现一个小功能,找了无数插件,终于选定一个后,项目迭代更新,原来的插件不够用了,又要继续找下去。
一个项目会用到很多插件,这些插件很可能没有完整的文档,没有统一的api,这又再次增加了维护的难度。

所以我们专门维护了一套组件库,其中多数是自己开发,少数是封装一些广受认可的组件,然后在项目中特定的功能强制要求使用特定组件的来实现,包括所有页面布局,div + css在这里已经被淘汰。当功能需求变更时,只需要升级对应的组件即可。只有这样才能让开发人员将精力放到业务逻辑上,而不是在一些旁枝末节的地方。

我们致力于开发高质量的跨平台应用,业务联系请参考官网。
http://www.mokekeji.com

收起阅读 »

顶部选项卡-可左右拖动(webview):用这个的时候webviewGroup 出现一个页面无法打开,只有点返回,才会出现页面。

mui

顶部选项卡-可左右拖动(webview)

tab-top-webview-main.html
问题:用这个的时候webviewGroup 出现一个页面无法打开,只有点返回,才会出现页面。

解决方法:
var group = new webviewGroup("viewgroup", {
换为
var group = new webviewGroup(plus.webview.currentWebview().id,{

继续阅读 »

顶部选项卡-可左右拖动(webview)

tab-top-webview-main.html
问题:用这个的时候webviewGroup 出现一个页面无法打开,只有点返回,才会出现页面。

解决方法:
var group = new webviewGroup("viewgroup", {
换为
var group = new webviewGroup(plus.webview.currentWebview().id,{

收起阅读 »

使用阿里云图标做的漂亮九宫格

导航 mui

使用阿里云图标做的漂亮九宫格
<ul class="mui-table-view mui-grid-view mui-grid-9">
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon iconfont icon-tianmao"></span>
<div class="mui-media-body">天猫</div>
</a>
</li>
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon iconfont icon-waimai1"><span class="mui-badge">5</span></span>
<div class="mui-media-body">外卖</div>
</a>
</li>
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon iconfont icon-juhuasuan"></span>
<div class="mui-media-body">聚划算</div>
</a>
</li>
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon iconfont icon-chong"></span>
<div class="mui-media-body">充值</div>
</a>
</li>
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon iconfont icon-feizhulvhang"></span>
<div class="mui-media-body">飞猪旅行</div>
</a>
</li>
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon iconfont icon-class" ></span>
<div class="mui-media-body">分类</div>
</a>
</li>

        </ul>
继续阅读 »

使用阿里云图标做的漂亮九宫格
<ul class="mui-table-view mui-grid-view mui-grid-9">
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon iconfont icon-tianmao"></span>
<div class="mui-media-body">天猫</div>
</a>
</li>
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon iconfont icon-waimai1"><span class="mui-badge">5</span></span>
<div class="mui-media-body">外卖</div>
</a>
</li>
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon iconfont icon-juhuasuan"></span>
<div class="mui-media-body">聚划算</div>
</a>
</li>
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon iconfont icon-chong"></span>
<div class="mui-media-body">充值</div>
</a>
</li>
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon iconfont icon-feizhulvhang"></span>
<div class="mui-media-body">飞猪旅行</div>
</a>
</li>
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon iconfont icon-class" ></span>
<div class="mui-media-body">分类</div>
</a>
</li>

        </ul>
收起阅读 »