微信支付(公众号支付接入方式)

首先准备几个工具类:HttpRequest请求工具类,MD5加密工具类,随机数生成工具类,签名生成工具类,xml格式转换类

package net.tiantianup.wap.utils.weixinpay;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.*;
import java.security.cert.CertificateException;

/**
 * Created by LV on 2016/4/11 0011.
 * Email:[email protected]
 */
public class HttpRequest {
    /**
     * 请求工具类(使用httpclient)
     * @param requestUrl 请求的API的URL
     * @param postData  需要发送的内容
     * @param certLocalPath PKCS12证书地址
     * @param certPassword  证书密码
     * @return
     * @throws CertificateException
     * @throws NoSuchAlgorithmException
     * @throws KeyStoreException
     * @throws IOException
     * @throws KeyManagementException
     * @throws UnrecoverableKeyException
     */
    public static String httpRequest(String requestUrl, String postData, String certLocalPath, String certPassword) throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException, UnrecoverableKeyException {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        FileInputStream instream = new FileInputStream(new File(certLocalPath));//加载本地的证书进行https加密传输
        try {
            keyStore.load(instream, certPassword.toCharArray());//设置证书密码
        } catch (CertificateException e) {
            e.printStackTrace();
        } finally {
            instream.close();
        }

        // Trust own CA and all self-signed certs
        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, certPassword.toCharArray())
                .build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext,
                new String[] { "TLSv1" },
                null,
                SSLConnectionSocketFactory.getDefaultHostnameVerifier());
        CloseableHttpClient httpclient = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .build();

        HttpPost httpPost=new HttpPost(requestUrl);

        //得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
        StringEntity postEntity = new StringEntity(postData, "UTF-8");
        httpPost.addHeader("Content-Type", "text/xml");
        httpPost.setEntity(postEntity);

        //设置请求器的配置
        httpPost.setConfig(RequestConfig.custom().setSocketTimeout(10000).setConnectTimeout(3000).build());

        HttpResponse response=httpclient.execute(httpPost);
        HttpEntity entity=response.getEntity();
        String result= EntityUtils.toString(entity);

        return result;
    }
}
package net.tiantianup.wap.utils.weixinpay;

import java.security.MessageDigest;

/**
 * MD5加密工具
 */
public class MD5 {
    private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
            "8", "9", "a", "b", "c", "d", "e", "f"};

    /**
     * 转换字节数组为16进制字串
     * @param b 字节数组
     * @return 16进制字串
     */
    public static String byteArrayToHexString(byte[] b) {
        StringBuilder resultSb = new StringBuilder();
        for (byte aB : b) {
            resultSb.append(byteToHexString(aB));
        }
        return resultSb.toString();
    }

    /**
     * 转换byte到16进制
     * @param b 要转换的byte
     * @return 16进制格式
     */
    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n = 256 + n;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    /**
     * MD5编码
     * @param origin 原始字符串
     * @return 经过MD5加密之后的结果
     */
    public static String MD5Encode(String origin) {
        String resultString = null;
        try {
            resultString = origin;
            MessageDigest md = MessageDigest.getInstance("MD5");
            resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultString;
    }

}
package net.tiantianup.wap.utils.weixinpay;

import java.util.Random;

/**
 * 随机数自动生成器
 */
public class RandomStringGenerator {

    /**
     * 获取一定长度的随机字符串
     * @param length 指定字符串长度
     * @return 一定长度的字符串
     */
    public static String getRandomStringByLength(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

}
package net.tiantianup.wap.utils.weixinpay;

import org.apache.log4j.Logger;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;

/**
 * Created by LV on 2016/4/7 0007.
 * Email:[email protected]
 */
public class SignUtil {
    /**
     * 签名算法
     * @param o 要参与签名的数据对象
     * @return 签名
     * @throws IllegalAccessException
     */
    public static Logger log=Logger.getLogger(SignUtil.class);

    public static String getSign(Object o,String key) throws IllegalAccessException {
        ArrayList<String> list = new ArrayList<String>();
        Class cls = o.getClass();
        Field[] fields = cls.getDeclaredFields();
        for (Field f : fields) {
            f.setAccessible(true);
            if (f.get(o) != null && f.get(o) != "") {
                list.add(f.getName() + "=" + f.get(o) + "&");
            }
        }
        int size = list.size();
        String [] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < size; i ++) {
            sb.append(arrayToSort[i]);
        }
        String result = sb.toString();
        result += "key=" + key;
        log.info("Sign Before MD5:" + result);
        result = MD5.MD5Encode(result).toUpperCase();
        log.info("Sign Result:" + result);
        return result;
    }

    /**
     * 将map对象进行签名
     * @param map
     * @return
     */
    public static String getSign(Map<String,Object> map,String key){
        ArrayList<String> list = new ArrayList<String>();
        for(Map.Entry<String,Object> entry:map.entrySet()){
            if(entry.getValue()!=""){
                list.add(entry.getKey() + "=" + entry.getValue() + "&");
            }
        }
        int size = list.size();
        String [] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < size; i ++) {
            sb.append(arrayToSort[i]);
        }
        String result = sb.toString();
        result += "key=" + key;
        log.info("Sign Before MD5:" + result);
        result = MD5.MD5Encode(result).toUpperCase();
        log.info("Sign Result:" + result);
        return result;
    }

    /**
     * 从API返回的XML数据里面重新计算一次签名
     * @param responseString API返回的XML数据
     * @return
     */
    public static String getSignFromResponseString(String responseString,String key) throws IOException, SAXException, ParserConfigurationException {
        Map<String,Object> map = XMLParser.getMapFromXML(responseString);
        //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
        map.put("sign","");
        //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
        return SignUtil.getSign(map,key);
    }

    /**
     * 检验API返回的数据里面的签名是否合法,避免数据在传输的过程中被第三方篡改
     * @param responseString API返回的XML数据字符串
     * @return API签名是否合法
     * @throws ParserConfigurationException
     * @throws IOException
     * @throws SAXException
     */
    public static boolean checkIsSignValidFromResponseString(String responseString,String key) throws ParserConfigurationException, IOException, SAXException {

        Map<String,Object> map = XMLParser.getMapFromXML(responseString);
        log.info(map.toString());

        String signFromAPIResponse = map.get("sign").toString();
        if(signFromAPIResponse=="" || signFromAPIResponse == null){
            log.info("API返回的数据签名数据不存在,有可能被第三方篡改!!!");
            return false;
        }
        log.info("服务器回包里面的签名是:" + signFromAPIResponse);
        //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
        map.put("sign","");
        //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
        String signForAPIResponse = SignUtil.getSign(map,key);

        if(!signForAPIResponse.equals(signFromAPIResponse)){
            //签名验不过,表示这个API返回的数据有可能已经被篡改了
            log.info("API返回的数据签名验证不通过,有可能被第三方篡改!!!");
            return false;
        }
       log.info("恭喜,API返回的数据签名验证通过!!!");
        return true;
    }
}
package net.tiantianup.wap.utils.weixinpay;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Created by LV on 2016/4/7 0007.
 * Email:[email protected]
 */
public class XMLParser {

    private static Logger log=Logger.getLogger(XMLParser.class);
    /**
     * 将返回的xml的数据转换成map
     * @param xmlString
     * @return
     * @throws ParserConfigurationException
     * @throws IOException
     * @throws SAXException
     */
    public static Map<String,Object> getMapFromXML(String xmlString) throws ParserConfigurationException, IOException, SAXException {

        //这里用Dom的方式解析回包的最主要目的是防止API新增回包字段
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        InputStream is =  Util.getStringStream(xmlString);
        Document document = builder.parse(is);

        //获取到document里面的全部结点
        NodeList allNodes = document.getFirstChild().getChildNodes();
        Node node;
        Map<String, Object> map = new HashMap<String, Object>();
        int i=0;
        while (i < allNodes.getLength()) {
            node = allNodes.item(i);
            if(node instanceof Element){
                map.put(node.getNodeName(),node.getTextContent());
            }
            i++;
        }
        return map;

    }

    /**
     * 商户处理后同步返回给微信参数,转换成xml类型
     * @param return_code
     * @param return_msg
     * @return
     */
    public static String setXML(String return_code,String return_msg) {
        return "<xml><return_code><![CDATA[" + return_code +
                "]]></return_code><return_msg><![CDATA[" +
                return_msg + "]]></return_msg></xml>";

    }

    public static String mapToXML(Map<String,Object> map){
        //将map类型的请求参数装换成XML格式
        StringBuilder sb=new StringBuilder();
        sb.append("<xml>");
        Iterator it=map.entrySet().iterator();
        while (it.hasNext()){
            Map.Entry entry= (Map.Entry) it.next();
            String k= (String) entry.getKey();
            String v= (String) entry.getValue();
            sb.append("<"+k+">"+v+"</"+k+">");
        }
        sb.append("</xml>");
        log.info("转换xml格式:"+sb.toString());
        return sb.toString();
    }

}

然后支付具体业务需按照需求来定制,下面的业务是本人开发的项目需求里的例子:

/**
     * 异步发起提交订单
     * @param courseApplyId
     * @param request
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/course/courseWxPayAjax/{courseApplyId}" ,method = RequestMethod.GET)
    public String courseWxPayAjax(@PathVariable("courseApplyId") String courseApplyId,HttpServletRequest request) throws IOException, SAXException, ParserConfigurationException, IllegalAccessException {
        //判断是否是微信客户端
        String userAgent = request.getHeader("User-Agent");
        if (userAgent.indexOf("MicroMessenger") > 0){
            //获取当前用户信息
            Subject currentUser = SecurityUtils.getSubject();//获取当前用户
            Session session = currentUser.getSession();
            CurrentUserModel currentUserModel = JSONObject.parseObject(session.getAttribute("user").toString(),CurrentUserModel.class);
            //获取申请的课程信息
            CourseApply courseApply=courseApplyService.getCourseApplyByCourseAppId(courseApplyId);
            //获取课程信息
            Course course=courseService.getCourseByCourseId(courseApply.getCourseId());

            /**微信支付请求参数*/
            Map<String,Object> requestParm=new TreeMap<>();
            requestParm.put("appid","wx0071d459ab95ac0f");//公众账号ID
            requestParm.put("attach",courseApplyId);//附加数据我们带上支付的课程申请ID,方便我们在微信支付回调后对数据库进行操作
            requestParm.put("body",course.getCourseName());//商品描述:课程名
            requestParm.put("mch_id","商户号》填上申请的商户号");//商户号
            requestParm.put("nonce_str",RandomStringGenerator.getRandomStringByLength(32));//随机字符串
            requestParm.put("notify_url","http://wap.zhaorenxue.com/course/paySuccess");//接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。
            requestParm.put("openid",currentUserModel.getOpenId());//trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识
            requestParm.put("out_trade_no",RandomStringGenerator.getRandomStringByLength(32));//out_trade_no商户订单号
            requestParm.put("spbill_create_ip", IPTools.getIpAddr(request));//APP和网页支付提交用户端ip
            requestParm.put("total_fee",String.valueOf((int)(course.getCoursePrice()*100)));//订单总金额,微信支付是1分钱为单位的
            requestParm.put("trade_type","JSAPI");//JSAPI--公众号支付
            String sign= SignUtil.getSign(requestParm,key);//生成签名
            requestParm.put("sign",sign);

            /**微信支付请求参数*/
            log.info("微信支付请求参数:"+requestParm.toString());

            //将需要发送给API的参数转换成规定的xml类型
            String requestXml= XMLParser.mapToXML(requestParm);
            /**请求参数转换成xml格式*/
            log.info("请求参数转换成xml格式:"+requestXml);

            /**调用微信请求的API*/
            //证书在服务器上面的路径
            String certLocalPath="/var/www/wap/WEB-INF/classes/apiclient_cert.p12";//证书在服务器上的地址,此应用部署的服务器上证书的具体地址------------------

            String responseXml=null;
                        try {
                    responseXml= HttpRequest.httpRequest("https://api.mch.weixin.qq.com/pay/unifiedorder",requestXml,certLocalPath,"证书密码,自己根据具体的密码填写");
                    //返回的xml格式数据
                    log.info("返回的xml格式数据:"+responseXml);

            } catch (Exception e) {
                return null;//如果请求失败,说明请求过程发生了错误,我们在返回的页面做处理
            }

           /* //模拟返回的xml数据
            String responseXml="<xml>" +
                    "   <return_code><![CDATA[SUCCESS]]></return_code>" +
                    "   <return_msg><![CDATA[OK]]></return_msg>" +
                    "   <appid><![CDATA[wx00]]></appid>" +
                    "   <mch_id><![CDATA[131]]></mch_id>" +
                    "   <nonce_str><![CDATA["+requestParm.get("nonce_str")+"]]></nonce_str>" +
                    "   <sign><![CDATA["+sign+"]]></sign>" +
                    "   <result_code><![CDATA[SUCCESS]]></result_code>" +
                    "   <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>" +
                    "   <trade_type><![CDATA[JSAPI]]></trade_type>" +
                    "</xml>";*/

            /**将返回的xml转换map格式*/
            Map<String,Object> responseMap=XMLParser.getMapFromXML(responseXml);
            /**返回数据转换成map格式*/
            log.info("返回数据转换成map格式:"+responseMap.toString());

            /**查看签名是否被修改*/
            if(SignUtil.checkIsSignValidFromResponseString(responseXml,key)){
                /**没有修改就做下一步判断*/
                //result_code成功时才会返回prepay_id
                if(responseMap.get("result_code").toString().equalsIgnoreCase("SUCCESS")){
                    //添加发起时间
                    CourseApply courseApplyTime=new CourseApply();
                    courseApplyTime.setApplyId(courseApplyId);
                    courseApplyTime.setPrePayTime(new Date());
                    courseApplyService.updateCourseApply(courseApplyTime);

                    //给微信JSAPI准备发送数据
                    Map<String,Object> parameters=new TreeMap<>();
                    parameters.put("appId","此处按申请的账号填写");
                    parameters.put("timeStamp",Long.toString(new Date().getTime()));
                    parameters.put("nonceStr", RandomStringGenerator.getRandomStringByLength(32));
                    parameters.put("package","prepay_id="+responseMap.get("prepay_id").toString());
                    parameters.put("signType","MD5");
                    String paySign=SignUtil.getSign(parameters,key);
                    parameters.put("paySign",paySign);//用签名算法算出来的
                    //当前微信浏览器的版本,5.0以上才支持微信支付
                    char agent=userAgent.charAt(userAgent.indexOf("MicroMessenger")+15);
                    parameters.put("agent",new String(new char[]{agent}));
                   // parameters.put("agent","5.5");//测试时写死
                    parameters.put("sendUrl","course/checkPaySuccess");//支付成功的回调地址----我们回调时可以查询一下数据库,是否支付成功,如果没有支付成功,返回到支付页面再支付---TODO

                    /**为支付JSAPI准备的数据*/
                    log.info("为支付JSAPI准备的数据:"+parameters.toString());

                    return JSONObject.toJSONString(parameters);
                }
            }
        }

        return null;
    }

代码里的商户号,appid,证书的路径,证书密码都按申请的账号填写,其中的签名key需要在微信商户号里自行设置

回调函数方法:

/**
     * 微信支付完成后,通知的支付结果notify_url,由微信服务器请求的异步地址(LV)
     */
    @ResponseBody
    @RequestMapping(value = "/course/paySuccess")
    public void paySuccess(HttpServletRequest request, HttpServletResponse response) throws IOException, ParserConfigurationException, SAXException {

        InputStream inputStream=request.getInputStream();

        ByteArrayOutputStream outStream=new ByteArrayOutputStream();
        byte[] buffer=new byte[1024];
        int len;
        while((len=inputStream.read(buffer))!=-1){
            outStream.write(buffer,0,len);
        }
        outStream.close();
        inputStream.close();

        String result=new String(outStream.toByteArray(),"utf-8");

        /**通知的支付结果notify_url返回的数据*/
        log.info("notify_url返回的数据:"+result);

        Map<String,Object> map= XMLParser.getMapFromXML(result);//返回数据转换成map

        log.info("notify_url返回的数据转换map格式:"+map.toString());

        if(map.get("result_code").toString().equalsIgnoreCase("SUCCESS")){
            //TODO 对数据库进行操作
            //获取放入attach的课程申请ID
            String courseApplyId=map.get("attach").toString();

            CourseApply courseApply=new CourseApply();
            courseApply.setApplyId(courseApplyId);
            courseApply.setApplyStatus(1);
            courseApply.setPayType(0);
            courseApply.setPayStatus(1);
            courseApply.setPayTime(new Date());
            courseApply.setPayment("WXOPENPAY");//微信公众平台支付
            courseApply.setOutTradeNo(map.get("out_trade_no").toString());
            courseApply.setTransactionId(map.get("transaction_id").toString());
            courseApply.setAppid(map.get("appid").toString());
            courseApply.setMchId(map.get("mch_id").toString());
            //将课程的支付的几个参数设置成已支付的状态
            courseApplyService.updateCourseApply(courseApply);

            //告诉微信服务器,支付完成
            response.getWriter().write(XMLParser.setXML("SUCCESS","OK"));

        }
    }

jsAPI中支付成功后的检查数据库的动作

 /**
     * sendUrl 在jsAPI中如果支付成功,我们再次验证一下,是否支付成功
     * @param model
     * @param courseApplyId
     * @return
     */
    @RequestMapping(value = "/course/checkPaySuccess/{courseApplyId}",method = RequestMethod.GET)
    public String checkPaySuccess(Model model,@PathVariable("courseApplyId") String courseApplyId){
        log.info("支付成功,检验数据库是否插入数据成功,已支付就跳转到支付成功页面");
        CourseApply courseApply=courseApplyService.getCourseApplyByCourseAppId(courseApplyId);
        int payStatus=courseApply.getPayStatus();
        model.addAttribute("courseApply",courseApply);
        if (payStatus==1){

            //使用返现码,生成返现记录(add by zzy)
            //获取当前用户信息
            Subject currentUser = SecurityUtils.getSubject();//获取当前用户
            Session session = currentUser.getSession();

            if(session.getAttribute("user")!=null) {
                CurrentUserModel currentUserModel = JSONObject.parseObject(session.getAttribute("user").toString(), CurrentUserModel.class);

                List<UserCoupon> list = userCouponService.getCouponByUserId(currentUserModel.getUserId());
                if (list != null && list.size() > 0) {
                    UserCoupon coupon = list.get(0);

                    User user = userService.getUserByUserId(currentUserModel.getUserId());
                    Course course = courseService.getCourseByCourseId(courseApply.getCourseId());

                    CashBackRecord cashBackRecord = new CashBackRecord();
                    cashBackRecord.setRecordId(UUID.randomUUID().toString());
                    cashBackRecord.setCouponNum(coupon.getCouponCode());
                    cashBackRecord.setMoney(course.getCoursePrice() / 10);//返现10%
                    cashBackRecord.setCreateTime(new Date());
                    cashBackRecord.setUserName(user.getNickname());
                    cashBackRecord.setUserId(user.getUserId());
                    cashBackRecord.setCourseId(course.getCourseId());

                    coupon.setIsUsed(1);
                    user.setMoney(user.getMoney() + course.getCoursePrice() / 10);

                    //生成返现记录
                    cashBackRecordService.saveCashBackRecord(cashBackRecord);
                    //更新余额
                    userService.updateUser(user);
                    //更改优惠码使用状态
                    userCouponService.updateCoupon(coupon);
                }
            }

            //数据库有支付记录,返回到成功页面
            return "pay_result";
        }
        //数据库没有支付记录,返回错误页面
        return "pay_error";
    }

在jsp中用ajax发起支付,页面中要引入jsapi自己的js文件

 <script src="https://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
    <script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
    <script>
        $(function($) {
            $("a[name=‘wxpay‘]").click(
                    function () {
                        //alert("${ctx}/course/courseWxPayAjax/${courseApplyId}");
                        $.ajax({
                            type: "GET",
                            url: "${ctx}/course/courseWxPayAjax/${courseApplyId}",
                            dataType: "JSON",
                            success: function(data){
                                //alert(data);
                                //alert("${ctx}/"+data.sendUrl+"/${courseApplyId}");
                                if(parseInt(data.agent)<5){
                                    alert("你的微信版本低于5.0,不能使用微信支付");
                                    return;
                                }
                                //调用微信支付控件完成支付
                                function onBridgeReady(){
                                    WeixinJSBridge.invoke(
                                            ‘getBrandWCPayRequest‘,{
                                                "appId":data.appId,     //公众号名称,由商户传入
                                                "timeStamp":data.timeStamp,         //时间戳,自1970年以来的秒数
                                                "nonceStr":data.nonceStr, //随机串
                                                "package":data.package,
                                                "signType":data.signType,         //微信签名方式:
                                                "paySign":data.paySign //微信签名
                                            },
                                            function(res){// 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回    ok,但并不保证它绝对可靠。
                                                //alert("支付成功"+res.err_msg);
                                                if(res.err_msg == "get_brand_wcpay_request:ok" ) {
                                                    //alert("判断成功");
                                                    //跳转到设置的支付成功页面url
                                                    window.location.href="${ctx}/"+data.sendUrl+"/${courseApplyId}";
                                                }else {
                                                    //alert("fail");
                                                    // window.location.href="";//跳转到支付页面继续支付
                                                }
                                            }
                                    );
                                }
                                if (typeof WeixinJSBridge == "undefined"){
                                    if( document.addEventListener ){
                                        document.addEventListener(‘WeixinJSBridgeReady‘, onBridgeReady, false);
                                    }else if (document.attachEvent){
                                        document.attachEvent(‘WeixinJSBridgeReady‘, onBridgeReady);
                                        document.attachEvent(‘onWeixinJSBridgeReady‘, onBridgeReady);
                                    }
                                }else{
                                    onBridgeReady();
                                }

                            }
                        });
                    }
            )
        })

    </script>

注意:在微信支付平台中设置支付目录,其中有测试目录和正式目录,如果是测试目录,只有添加进白名单的微信号才能完成支付,使用正式目录,只要是微信用户都可以完成支付。

${ctx}/course/courseWxPayAjax/${courseApplyId}

那么设置的支付目录是:
域名/${ctx}/course
时间: 2024-10-06 00:20:13

微信支付(公众号支付接入方式)的相关文章

微信支付公众号支付redirect_uri域名与后台配置不一致,错误码10003

最近弄微信支付,微信支付公众号支付redirect_uri域名与后台配置不一致,错误码10003,最容易出错两个地方 1,appid 对应不到 2,开发者网页授权 填写域名 文章来自http://www.96net.com.cn 原文地址:https://www.cnblogs.com/96net/p/9648188.html

微信支付-公众号支付H5调用支付详解

微信公众号支付 最近项目需要微信支付,然后看了下微信公众号支付,,虽然不难,但是细节还是需要注意的,用了大半天时间写了个demo,并且完整的测试了一下支付流程,下面分享一下微信公众号支付的经验. 一.配置公众号微信支付 需要我们配置微信公众号支付地址和测试白名单. 比如:支付JS页面的地址为 http://www.xxx.com/shop/pay/ 那此处配置www.xxx.com/shop/pay/ 二.开发流程 借用微信公众号支付api(地址 http://pay.weixin.qq.com

企业号微信支付 公众号支付 H5调起支付API示例代码 JSSDK C# .NET

先看效果: 1.本文演示的是微信[企业号]的H5页面微信支付 2.本项目基于开源微信框架WeiXinMPSDK开发:https://github.com/JeffreySu/WeiXinMPSDK 感谢作者苏志巍的开源精神 一.准备部分 相关参数: AppId:公众号的唯一标识(登陆微信企业号后台 - 设置 - 账号信息 - CorpID) AppSecret:(微信企业号后台 - 设置 - 权限管理 - 新建一个拥有所有应用权限的普通管理组 - Secret) Key:商户API密钥(登陆微信

微信支付-公众号支付,统一下单,调起微信支付,回调验证

参考:http://www.jianshu.com/p/a172a1b69fdd http://www.jianshu.com/p/1ae0ef652f63 http://www.jb51.net/article/76110.htm http://www.tangshuang.net/2359.html http://wyong.blog.51cto.com/1115465/1692322 常见问题http://kf.qq.com/faq/140225MveaUz150413VNj6nm.htm

微信公众号支付H5-java版代码

1,工具类 package net.jeeshop.core.util; import org.jdom.Document;import org.jdom.Element;import org.jdom.JDOMException;import org.jdom.input.SAXBuilder; import java.io.*;import java.math.BigDecimal;import java.net.ConnectException;import java.net.HttpUR

转-微信支付(公众号支付JSAPI)

原文路径:https://blog.csdn.net/javaYouCome/article/details/79473743 写这篇文章的目的有2个,一是自己的项目刚开发完微信支付功能,趁热回个炉温习一下,二也是帮助像我这样对微信支付不熟悉,反复看了多天文档还是一知半解,原理都没摸清,更不要说实现了.本以为网上的微信开发教程会和"java的重写与重载"一样铺天盖地,可搜出来的结果,要么是PHP的教程(微信支付官网推荐就是PHP),要么星星点点就那么几篇,想对比的看看思路都成问题,官网

8. PHP接入微信的三种支付:APP支付、公众号支付、扫码支付

微信的支付逻辑与支付宝的支付有一些差别.为了让客户端忽略这些差别,统一调用.本sdk做了对应处理. # SDK调用 微信支付不同接口需要的参数会有差别.请大家在使用接口时,仔细查看文档. use Payment\ChargeContext; use Payment\Config; use Payment\Common\PayException; // 微信支付,必须设置时区,否则发生错误 date_default_timezone_set('Asia/Shanghai'); // 生成订单号 便

微信支付之扫码支付、公众号支付、H5支付、小程序支付相关业务流程分析总结

前言 很久以来,一直想写一篇微信支付有关的总结文档:一方面是总结自己的一些心得,另一方面也可以帮助别人,但是因种种原因未能完全理解透彻微信支付的几大支付方式,今天有幸做一些总结上的文章,也趁此机会,将一年多以来的相关经验分享一下. 概述 1. 扫码支付 商户在pc端展示一个支付二维码,用户使用微信扫一扫功能,扫码后实现付款的支付方式. 2. 公众号支付 商户在微信APP内(微信浏览器)打开H5网页,通过微信支付实现付款的支付方式. 3. H5支付 商户在微信浏览器以外的手机浏览器打开H5网页,通

C# MVC 微信支付教程系列之公众号支付

微信支付教程系列之公众号支付   今天,我们接着讲微信支付的系列教程,前面,我们讲了这个微信红包和扫码支付.现在,我们讲讲这个公众号支付.公众号支付的应用环境常见的用户通过公众号,然后再通过公众号里面的菜单链接,进入公众号的商城,然后在里面完成购买和支付功能,我们可以看看官方对这个公众号支付的场景的解释,链接:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1,通过这个官方的解释,那我们大概清楚这个公众号的用途了,下面,我就说

2017-9月微信公众号支付-Java详解

微信支付源代码 在此之前,先C麻瓜藤N遍,MD官方文档一半正确一半错误.言归正传, 微信支付整体流程:微信授权登录商户的公众号--微信支付的公众号配置--统一下单--微信js调起支付页面--输入密码支付--支付成功,异步回调URL处理商户的相应业务 一.业务场景: 先看一下支付的业务场景:用户使用微信登录商户页面,点击支付按钮,调起微信支付,选择付款卡号,输入密码,完成支付,如图: 场景十分简单,不过步骤比较多,稍不注意就掉坑里了. 二.微信公众号支付的配置准备: 1)调用公众号支付,首先你得有