利用java代码实现的微信在线支付功能

微信成了我们日常生活中常用的一款手机APP软件,做为程序员的我们肯定也会有些客户需要对微信进行二次开发的,其中对微信的支付开发就是我们常见的一种。在对微信进行支付开发之前,首先你的公众号是企业或单位服务号。并且要开通每年300元一次的认证,才有开通支付功能的权限。有了这个权限我们就教大家如何在JAVA中实现对微信公众号的支付开发。
APP_ID和APP_SECRET在公众平台 
MCH_ID和API_KEY在商户平台,其中API_KEY是自己设置的,并不是自动生成的。


Controller
通过此方法,前往可以生成二维码的页面


//微信前往支付页面


    @RequestMapping(value = "towxPay")
    public ModelAndView towxPay(ModelMap map,HttpServletRequest request,String chapterId,String chapterName,String price) throws IOException{
        ModelAndView mav = new ModelAndView();
        mav.setViewName("jsp/pay/weixinpayma");
        HttpSession session = request.getSession();
        session.setAttribute("chapterId", chapterId);
        session.setAttribute("chapterName", chapterName);
        session.setAttribute("price", price);
        return mav;
    }


返回的页面如下

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
                <%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
            + path + "/";
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="<%=basePath%>js/jquery-3.1.1.min.js"></script>
</head>
<body>
     <div id="wxpayma">
     <!-- 访问Controller的index/payImg方法,将生成的二维码图片显示在这 -->
        <img alt="" src="<%=basePath%>index/payImg"> 
    </div> 
    <script>
    /* ajax轮回,不停的访问Controller,直到wxPayType=1时,付款成功 */
         var num = 0;
        $(function(){
             panduanWXPay();
        }); 
        function panduanWXPay(){
            $.post("<%=basePath%>index/panduanPay",function(data){
                var wxPayType = data.wxPayType;
                if(wxPayType==1){
                /* 成功 */
                    window.location.href='<%=basePath%>index/gouMai';
                }else if(wxPayType==0 && num!=400){
                     num++;
                     panduanWXPay();
                }else{
                    alert("支付超时");
                }
            });
        }  
    </script>
</body>
</html>


payImg方法
//微信支付,生成二维码
    @RequestMapping(value = "payImg")
    public  void payImg(HttpServletRequest request, HttpServletResponse response) throws IOException{
        HttpSession session = request.getSession();
        String chapterName=(String)session.getAttribute("chapterName");
        String price=(String)session.getAttribute("price");
        int defaultWidthAndHeight=200;
        String nonce_str = PayCommonUtil.getNonce_str();
        long time_stamp = System.currentTimeMillis() / 1000;
        String product_id = chapterName+"*"+price;//订单名字和价钱,拼到了一起,后面用到的时候再拆
        String key = PayConfigUtil.API_KEY; // key
        SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
        packageParams.put("appid", PayConfigUtil.APP_ID);
        packageParams.put("mch_id", PayConfigUtil.MCH_ID);
        packageParams.put("time_stamp", String.valueOf(time_stamp));
        packageParams.put("nonce_str", nonce_str);
        packageParams.put("product_id", product_id);
//      packageParams.put("chapterId", chapterId);
//      packageParams.put("price", price);
        String sign = PayCommonUtil.createSign("UTF-8", packageParams,key);//MD5哈希
        packageParams.put("sign", sign); 
        //生成参数
        String str = ToUrlParams(packageParams);
        String payurl = "weixin://wxpay/bizpayurl?" + str;
//      logger.info("payurl:"+payurl);
        //生成二维码
        Map<EncodeHintType, Object>  hints=new HashMap<EncodeHintType, Object>();
        // 指定纠错等级  
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);  
        // 指定编码格式  
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");  
        hints.put(EncodeHintType.MARGIN, 1);
        try {
            BitMatrix bitMatrix = new MultiFormatWriter().encode(payurl,BarcodeFormat.QR_CODE, defaultWidthAndHeight, defaultWidthAndHeight, hints);
            OutputStream out = response.getOutputStream();
            MatrixToImageWriter.writeToStream(bitMatrix, "png", out);//输出二维码
            out.flush();
            out.close();


        } catch (WriterException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


public String ToUrlParams(SortedMap<Object, Object> packageParams){
        //实际可以不排序,这里排序是为了能更好的读懂。
        StringBuffer sb = new StringBuffer();  
        Set es = packageParams.entrySet();  
        Iterator it = es.iterator();  
        while (it.hasNext()) {  
            Map.Entry entry = (Map.Entry) it.next();  
            String k = (String) entry.getKey();  
            String v = (String) entry.getValue();  
            if (null != v && !"".equals(v)) {  
                sb.append(k + "=" + v + "&");  
            }  
        }
        sb.deleteCharAt(sb.length()-1);//删掉最后一个&
        return sb.toString();
    }
扫码时触动此方法,会在手机端显示付款信息 
要将此方法的路径配置到回调url里,微信公众平台–>微信支付–>开发配置 
这里写图片描述


微信扫码的时候,触发此方法
    @RequestMapping(value = "Re_notify")
    public void Re_notify(HttpServletRequest request, HttpServletResponse response) throws IOException{
        HttpSession session = request.getSession();
        String chapterId=(String)session.getAttribute("chapterId");
        String chapterName=(String)session.getAttribute("chapterName");
        String price=(String)session.getAttribute("price");
        System.out.println(chapterId+":"+chapterName+":"+price);
        // 读取xml
                InputStream inputStream;
                StringBuffer sb = new StringBuffer();
                inputStream = request.getInputStream();
                String s;
                BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
                while ((s = in.readLine()) != null) {
                    sb.append(s);
                }
                in.close();
                inputStream.close();
                SortedMap<Object, Object> packageParams = PayCommonUtil.xmlConvertToMap(sb.toString());
//              logger.info(packageParams); 
                // 账号信息
                String key = PayConfigUtil.API_KEY; // key
                String resXml="";//反馈给微信服务器
                // 验签
                if (PayCommonUtil.isTenpaySign("UTF-8", packageParams, key)) {
                    //appid openid mch_id is_subscribe nonce_str product_id sign
                    //统一下单
                    String openid = (String)packageParams.get("openid");
                    String product_id = (String)packageParams.get("product_id");
                    //解析product_id,计算价格等
                    String thePricce = product_id.substring(product_id.lastIndexOf("*")+1);
                    String newProductId = product_id.substring(0, product_id.indexOf("*"));
                    String out_trade_no = String.valueOf(System.currentTimeMillis()); // 订单号  
                    String order_price = thePricce; // 价格"1"   注意:价格的单位是分  
                    String body = newProductId;   // 商品名称product_id  这里设置为product_id
                    String attach = "十倍课"; //附加数据
                    String nonce_str0 = PayCommonUtil.getNonce_str();
                    // 获取发起电脑 ip  
                    String spbill_create_ip = PayConfigUtil.CREATE_IP;    
                    String trade_type = "NATIVE"; 
                    SortedMap<Object,Object> unifiedParams = new TreeMap<Object,Object>();  
                    unifiedParams.put("appid", PayConfigUtil.APP_ID); // 必须
                    unifiedParams.put("mch_id", PayConfigUtil.MCH_ID); // 必须
                    unifiedParams.put("out_trade_no", out_trade_no); // 必须
                    unifiedParams.put("product_id", product_id);
                    unifiedParams.put("body", body); // 必须
                    unifiedParams.put("attach", attach);
                    unifiedParams.put("total_fee", order_price);  // 必须 
                    unifiedParams.put("nonce_str", nonce_str0);  // 必须
                    unifiedParams.put("spbill_create_ip", spbill_create_ip); // 必须 
                    unifiedParams.put("trade_type", trade_type); // 必须  
                    unifiedParams.put("openid", openid);  
                    unifiedParams.put("notify_url", PayConfigUtil.NOTIFY_URL);//异步通知url
                    String sign0 = PayCommonUtil.createSign("UTF-8", unifiedParams,key);  
                    unifiedParams.put("sign", sign0); //签名
                    String requestXML = PayCommonUtil.getRequestXml(unifiedParams);  
//                  logger.info(requestXML);
                    //统一下单接口,让其他的操作方便调用。
                    String rXml = HttpUtil.postData(PayConfigUtil.UFDODER_URL, requestXML);  
                    //统一下单响应
                    SortedMap<Object, Object> reParams = PayCommonUtil.xmlConvertToMap(rXml);
//                  logger.info(reParams); 
                    //验签
                    if (PayCommonUtil.isTenpaySign("UTF-8", reParams, key)) {
                        // 统一下单返回的参数
                        String prepay_id = (String)reParams.get("prepay_id");//交易会话标识  2小时内有效
                        String nonce_str1 = PayCommonUtil.getNonce_str();
                        SortedMap<Object,Object> resParams = new TreeMap<Object,Object>();  
                        resParams.put("return_code", "SUCCESS"); // 必须
                        resParams.put("return_msg", "OK");
                        resParams.put("appid", PayConfigUtil.APP_ID); // 必须
                        resParams.put("mch_id", PayConfigUtil.MCH_ID);
                        resParams.put("nonce_str", nonce_str1); // 必须
                        resParams.put("prepay_id", prepay_id); // 必须
                        resParams.put("result_code", "SUCCESS"); // 必须
                        resParams.put("err_code_des", "OK");
                        String sign1 = PayCommonUtil.createSign("UTF-8", resParams,key);  
                        resParams.put("sign", sign1); //签名
                        resXml = PayCommonUtil.getRequestXml(resParams);
//                      logger.info(resXml);
                    }else{
//                      logger.info("签名验证错误");
                        resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"  
                                + "<return_msg><![CDATA[签名验证错误]]></return_msg>" + "</xml> "; 
                    }
                }else{
//                  logger.info("签名验证错误");
                    resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"  
                            + "<return_msg><![CDATA[签名验证错误]]></return_msg>" + "</xml> "; 
                }
                //------------------------------  
                //处理业务完毕  
                //------------------------------  
                BufferedOutputStream out = new BufferedOutputStream(  
                        response.getOutputStream());  
                out.write(resXml.getBytes());  
                out.flush();  
                out.close();  
    }


微信支付成功时访问的方法 
密码错误等未支付成功的情况下,不会访问。 
此路径是PayConfigUtil中配置的
int wxPayType = 0;
    //微信扫码支付回调
    @RequestMapping(value = "Notify1")
    public void Notify1(HttpServletRequest request, HttpServletResponse response) throws IOException{
        InputStream inputStream;
        StringBuffer sb = new StringBuffer();
        inputStream = request.getInputStream();
        String s;
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
        while ((s = in.readLine()) != null) {
            sb.append(s);
        }
        in.close();
        inputStream.close();
        SortedMap<Object, Object> packageParams = PayCommonUtil.xmlConvertToMap(sb.toString());
//      logger.info(packageParams);
        // 账号信息
        String key = PayConfigUtil.API_KEY; // key
        String resXml = ""; // 反馈给微信服务器
        // 判断签名是否正确
        if (PayCommonUtil.isTenpaySign("UTF-8", packageParams, key)) {
            // ------------------------------
            // 处理业务开始
            // ------------------------------
            if ("SUCCESS".equals((String) packageParams.get("result_code"))) {
                // 这里是支付成功
                ////////// 执行自己的业务逻辑////////////////
                String mch_id = (String) packageParams.get("mch_id");
                String openid = (String) packageParams.get("openid");
                String is_subscribe = (String) packageParams.get("is_subscribe");
                String out_trade_no = (String) packageParams.get("out_trade_no");
                String total_fee = (String) packageParams.get("total_fee");
//// 将用于标记是否成功的全局变量wxPayType设置为1,ajax轮回时,可以获取到其变化,从而进行页面跳转////
                wxPayType=1;
                System.out.println("33333333333333333333333333333:"+wxPayType);
//          "支付成功"
// 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
            } else {
//              logger.info("支付失败,错误信息:" + packageParams.get("err_code"));
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
            }
        } else {
//          logger.info("签名验证错误");
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"  
                    + "<return_msg><![CDATA[签名验证错误]]></return_msg>" + "</xml> "; 
        }
        // ------------------------------
        // 处理业务完毕
        // ------------------------------
        BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
        out.write(resXml.getBytes());
        out.flush();
        out.close();
    }


ajax不停轮回,判断是否登录成功的方法
@RequestMapping(value = "panduanPay")
        @ResponseBody
        public Map<String,Object> panduanPay(HttpServletRequest request) throws IOException{
            Map<String,Object> map = new HashMap<String,Object>();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            //给页面返回wxPayType值,成功是返回的是1;还未支付成功,返回的是初始值0
            map.put("wxPayType",wxPayType);
            return map;
        }
成功后页面跳转的方法
//购买成功,存入购买表中
    @RequestMapping(value="gouMai")
    @ResponseBody
    public ModelAndView gouMai(HttpServletRequest req,String a,String urlName,String couName,ModelMap map){
        ModelAndView mav = new ModelAndView();
        Map<String,String> mapp1 = new HashMap<String,String>();
//      SysUserTab login_user = sysuserService.getSysUserById(userId);
        HttpSession session = req.getSession();
        SysUserTab login_user1 = (SysUserTab) session.getAttribute("login_user");
        String userId = login_user1.getUserId();
//      session.setAttribute("login_user", login_user);
        String chapterId = (String) session.getAttribute("chapterId");
        mapp1.put("userId", userId);
        mapp1.put("chapterId", chapterId);
        int num = sysBuyService.getBuyCount(mapp1);
        if(num==0){
            mapp1.put("buyId", UUID.randomUUID().toString().replace("-", ""));
            sysBuyService.insertBuy(mapp1);
        }

总结
采用java实现微信的支付,还是有点麻烦。而且在调试阶段需要联网,并且抓包来了解数据库的传输原理。当然在支付的时候肯定的用SSL加密的数据库传输!

本文由作者自行上传发布,文章仅代表作者个人观点。如需转载,务必声明出处和网址,否则保留相关权利。

网友评论 comments

发表评论

电子邮件地址不会被公开。必填项已用 *标注

暂无评论

牛人技术博客 | About US | 湘ICP备13000282号-8 |
Copyright © 2009 - 2023 NRJS Corporation, All Rights Reserved
添加图标到手机桌面
扫二维码
扫二维码
返回顶部