JAVA微信现金红包开发教程

1.首先做微信方面的开发,一定需要详细的阅读微信支付的开发文档。因为里面列举了比如消息的触达规则,接口调用的请求说明,请求的参数,错误返回示例以及成功返回示例,阅读这些,在出错了我们能够快速定位并且解决问题。

https://pay.weixin.qq.com/wiki/doc/api/index.html


2.在开发微信红包之前,你首先肯定得准备好微信商户平台,微信公众号(服务号)(在这里假设你已经全部准备好了)。

3.我这个发送红包是大转盘抽奖,抽到了红包奖品之后,通知后台去发送红包。废话不多说,前端ajax代码:

//前端发送ajax请求,请求后台去发送红包,前后端交互采用的是json格式的数据进行传输。
var redPacketRequestJson = {
       "appid":$("#appid").val(),//该公众号的appid的值
       "openid":$("#openid").val(),//该用户的openid的值
       "redValue":$("#redValue").val()//红包的大小值,单位为分,最低为100分也就是一元
     };
$.ajax({
   type: "post",
   url: "http://localhost/wechat/sendRedPacket",
   contentType: "application/json; charset=utf-8",
   data: JSON.stringify(redPacketRequestJson),
   dataType: "json",
   success: function (data) {
   if(data.statusCode==100){
        console.log("红包发送成功")
    }
    },
   error: function (XMLHttpRequest, textStatus, errorThrown) {
          alert(XMLHttpRequest.status);
          alert(XMLHttpRequest.readyState);
          alert(textStatus);
         }
  });

后台的代码如下:

    @ResponseBody
    @RequestMapping("/sendRedPacket")
    public String sendRedPacket(@RequestBody(required = false) String requestJson, HttpServletRequest request){
        try{
            logger.info("发送红包的时候,前端传输过来的信息是:"+requestJson);
            JSONObject jsonObject = JSONObject.parseObject(requestJson);
            //公众号的appid
            String appid = jsonObject.getString("appid");
            /**
             * 根据APPID获取access_token
             * 我的access_token是做了一个定时器,每隔两个小时刷新一次access_token的值,
             * 并且保存在redis当中(需要详情的话请留言)。
             */
            String access_token = RedisUtil.getJustOneMapValueFromRedis(jedisPool,appid,"access_token");
            //发给谁,该用户的openid
            String openid = jsonObject.getString("openid");
            //红包的值,最低100分
            Integer redValue = jsonObject.getInteger("redValue");
            //开始发送红包
            logger.info("++++++++++++++开始发送红包++++++++++++++++++");
            SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
            /** 当前时间 yyyyMMddHHmmss */
            String currTime = CommonUtil.getCurrTime();
            /** 8位日期 */
            String strTime = currTime.substring(8, currTime.length());
            /** 四位随机数 */
            String strRandom = CommonUtil.buildRandom(4) + "";
            //商户订单号
            parameters.put("mch_billno",strTime + strRandom);
            /** 商户号 */
            String mch_id = Constants.mch_id;
            parameters.put("mch_id", mch_id);
            /** 随机字符串 */
            parameters.put("nonce_str", CommonUtil.getNonceStr());
            /** 公众号APPID */
            parameters.put("wxappid", appid);
            /** 商户名称 */
            String mch_name = "这个填你们申请微信支付的公众号的名称";
            parameters.put("send_name",mch_name);
            /** 用户openid */
            parameters.put("re_openid",openid);
            /** 付款金额 */
            parameters.put("total_amount",redValue);
            /** 红包发放总人数 */
            parameters.put("total_num",1);
            /** 红包祝福语 */
            parameters.put("wishing","感谢您参加抽奖活动,希望您再次中奖");
            /** 调用接口的机器Ip地址 */
            parameters.put("client_ip",request.getRemoteAddr());
            /** 活动名称 */
            String activityName = "这个填你们这个红包活动的名称";
            parameters.put("act_name",activityName);
            /** 备注 */
            parameters.put("remark","抽的多中的多,欢迎下次再来");
            /** 场景id  发放红包使用场景,红包金额大于200时必传
             * PRODUCT_1:商品促销 PRODUCT_2:抽奖 PRODUCT_4:企业内部福利  PRODUCT_5:渠道分润 */
            parameters.put("scene_id","PRODUCT_2");
            /** 资金授权商户号 */
            //parameters.put("consume_mch_id","");
            /** 活动信息  资金授权商户号,服务商替特约商户发放时使用*/
            //parameters.put("risk_info","");
            /** MD5进行签名,必须为UTF-8编码,注意上面几个参数名称的大小写 */
            String api_key = "这个填你们商户平台的支付密钥的信息";
            String sign = CommonUtil.createSign("UTF-8", parameters,api_key);
            String requestJsonStr = JSON.toJSONString(parameters);
            logger.info("发送的信息是"+requestJsonStr);
            parameters.put("sign", sign);//
            /** 生成xml结构的数据,用于统一下单接口的请求 */
            String requestXML = CommonUtil.getRequestXml(parameters);
            /**
             * 读取证书
             * 
             */
            CloseableHttpClient httpclient = null;
            Map<String,String> result = new HashMap<String,String>();
            try {
                KeyStore keyStore = KeyStore.getInstance("PKCS12");
                String pathname = "/usr/apiclient_cert.p12";//这里填你们的证书的地址,我这里放在linux服务器的/usr下面
                FileInputStream instream = new FileInputStream(new File(pathname)); //此处为证书所放的绝对路径
                try {
                    keyStore.load(instream, mch_id.toCharArray());
                } finally {
                    instream.close();
                }
                // Trust own CA and all self-signed certs
                SSLContext sslcontext = SSLContexts.custom()
                        .loadKeyMaterial(keyStore, mch_id.toCharArray())
                        .build();
                // Allow TLSv1 protocol only
                SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                        sslcontext,
                        new String[]{"TLSv1"},
                        null,
                        SSLConnectionSocketFactory.getDefaultHostnameVerifier());//SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
                httpclient = HttpClients.custom()
                        .setSSLSocketFactory(sslsf)
                        .build();
            }
            catch (Exception e){
                logger.info("读取证书信息的时候发生异常异常信息是:"+e.getMessage());
                e.printStackTrace();
            }
            try {
                String requestUrl = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
                HttpPost httpPost = new HttpPost(requestUrl);
                StringEntity reqEntity  = new StringEntity(requestXML, "utf-8");
                // 设置类型
                reqEntity.setContentType("application/x-www-form-urlencoded");
                httpPost.setEntity(reqEntity);
                logger.info("executing request" + httpPost.getRequestLine());
                CloseableHttpResponse response = httpclient.execute(httpPost);
                try {
                    HttpEntity entity = response.getEntity();
                    System.out.println(response.getStatusLine());
                    if (entity != null) {
                        // 从request中取得输入流
                        InputStream inputStream = entity.getContent();
                        // 读取输入流
                        SAXReader reader = new SAXReader();
                        Document document = reader.read(inputStream);
                        // 得到xml根元素
                        Element root = document.getRootElement();
                        // 得到根元素的所有子节点
                        List<Element> elementList = root.elements();
                        // 遍历所有子节点
                        for (Element e : elementList)
                        {
                            result.put(e.getName(), e.getText());
                        }
                        // 释放资源
                        inputStream.close();
                    }
                    EntityUtils.consume(entity);
                }
                finally {
                    if(response!=null) {
                        response.close();
                    }
                }
            }
            catch (Exception e){
                e.printStackTrace();
            }finally {
                try {
                    httpclient.close();
                }
                catch (Exception e){
                    e.printStackTrace();
                }
            }
            logger.info("------------------发送红包结束---------------");
            logger.info("发送红包微信返回的信息是:"+JSON.toJSONString(result));
            //假如发送成功的话,保存发送的信息
            if(result.get("return_msg").equals("发放成功")) {
                logger.info("红包发放成功openid="+openid+",发送时间是:"+CommonUtil.getPreDay(new Date(),0));
                return ApiResponse.buildSuccessResponse(ResultConstant.OPERATOR_SUCCESS,ResultConstant.MESSAGE_OPERATE_SUCCESS,result);
                }
            else {
                logger.info("红包发放失败,openid="+openid+",发送时间是:"+CommonUtil.getPreDay(new Date(),0));
                return ApiResponse.buildFailResponse(ResultConstant.OPERATOR_FAIL,ResultConstant.MESSAGE_OPERATE_FAIL);
            }
        }
        catch (Exception e){
            logger.info("发送红包异常,异常信息是:"+e.getMessage());
            return ApiResponse.buildFailResponse(ResultConstant.OPERATOR_FAIL,ResultConstant.MESSAGE_SYSTEM_EXCEPTION);
        }
    }

其中,由于学习微信开发的时候看的参考书籍是柳峰老师的微信开发教程,所以工具类的名称是一样的,在这里把这里需要的一些方法罗列在下面(代码中需要的从上往下排列,在开发微信的其他模块也可能用的上的):

 /**
     * 获取当前时间 yyyyMMddHHmmss
     * @return String
     */
    public static String getCurrTime() {
        Date now = new Date();
        SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        String s = outFormat.format(now);
        return s;
    }
/**
     * 取出一个指定长度大小的随机正整数.
     *
     * @param length int 设定所取出随机数的长度。length小于11
     * @return int 返回生成的随机数。
     */
    public static int buildRandom(int length) {
        int num = 1;
        double random = Math.random();
        if (random < 0.1) {
            random = random + 0.1;
        }
        for (int i = 0; i < length; i++) {
            num = num * 10;
        }
        return (int) ((random * num));
    }
/**
     * 获取32位随机字符串
     *
     * @return
     */
    public static String getNonceStr() {
        Random random = new Random();
        return MD5Util.MD5Encode(String.valueOf(random.nextInt(10000)), "UTF-8");
    }
/**
     * 微信支付sign签名
     * @param characterEncoding
     * @param parameters
     * @return
     */
    public static String createSign(String characterEncoding, SortedMap<Object, Object> parameters,String api_key) {
        StringBuffer sb = new StringBuffer();
        Set<Map.Entry<Object, Object>> es = parameters.entrySet();
        Iterator<Map.Entry<Object, Object>> it = es.iterator();
        while (it.hasNext()) {
            Map.Entry<Object, Object> entry = (Map.Entry<Object, Object>) it.next();
            String k = (String) entry.getKey();
            Object v = entry.getValue();
            /** 如果参数为key或者sign,则不参与加密签名 */
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        System.out.println("传过来的支付密钥api_key="+api_key);
        /** 支付密钥必须参与加密,放在字符串最后面 */
        sb.append("key=" + api_key);
        /** 记得最后一定要转换为大写 */
        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
        return sign;
    }
/**
     * 将请求参数转换为xml格式的string
     * @param parameters
     * @return
     */
    public static String getRequestXml(SortedMap<Object, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set<Map.Entry<Object, Object>> es = parameters.entrySet();
        Iterator<Map.Entry<Object, Object>> it = es.iterator();
        while (it.hasNext()) {
            Map.Entry<Object, Object> entry = (Map.Entry<Object, Object>) it.next();
            String k = (String) entry.getKey();
            String v = entry.getValue() + "";
            if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
                sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
            } else {
                sb.append("<" + k + ">" + v + "</" + k + ">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }
 /**
     * 获取系统前一天的信息(amount=-1),当前时间(amount=0),后一天(amount=1)
     * @param date
     * @return
     */
    public static String getPreDay(Date date,Integer amount) {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, amount);
        date = calendar.getTime();
        String value = sdf.format(date);
        return value.split(" ")[0];
    }

其中一些需要注意的,比如api_key(即下图当中的API密钥),商户支付证书(下图中的下载证书)在你们的商户平台去设置和下载。


去产品中心-我的产品看下你的现金红包是否已经开通了,假如未开通有未开通的提示信息,然后去开通就行了。


点击这个现金红包,可以给现金红包进行一些设置,比如只允许某个IP调用现金红包API(感觉这个很重要)。


以上这些都弄好了,设置好了,去给自己发个红包吧!!!







猜你喜欢

转载自blog.csdn.net/qq_38455201/article/details/80223327