微信公众号发红包

踩过很多坑,希望这篇文可以为大家开发公众号领取红包,做个引导。更重要的是,我发现我有点忘了,所以为了下次再用到这方面的功能,特此,来做个记录

PS:可以多看看api文档,吐槽一下,微信开发api文档很坑,相比之下,支付宝api看着就舒服多了。

前期准备,公众号+有红包功能的商户号

因为没有可用的域名,所有我用了菜单点击事件

简单直接上代码,可以自己下载一个官方提供的源码对比着看。

   @RequestMapping(method = RequestMethod.POST)
    @ResponseBody
    public void weChatConnect(HttpServletRequest req, HttpServletResponse resp, HttpSession session) throws IOException{

        req.getInputStream();
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=utf-8");

        PrintWriter out=resp.getWriter();

        Map<String ,String> map= MessageUtil.xmlToMap(req);
        String fromUserName = map.get("FromUserName");
        String toUserName = map.get("ToUserName");
        String msgType = map.get("MsgType");
        String content = map.get("Content");

        session.setAttribute("requestMap",map);

        String message=null;

        System.out.println(msgType+",,,,"+map.get("Event"));

        try{

            //事件,消息自动推送
            if(Const.MsgType.MESSAGE_EVNET.equals(msgType)){
                //获取推送事件
                String eventType=map.get("Event");

                //菜单点击
                if(Const.MsgType.MESSAGE_CLICK.equals(eventType)){
                    String key=map.get("EventKey");
                    if(key.equals("sendredpack")){
                        //红包事件

                        sendRedPackController.sendRedPack(req,resp,map);
                    }

                }

            }
            out.print(message);

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            out.close();
        }

    }

 

红包领取controller

@Controller
@RequestMapping("/redhandle/")
public class SendRedPackController {

    private Logger logger = LoggerFactory.getLogger(SendRedPackController.class);

    @Autowired
    private ISendRedPackService iSendRedPackService;

    @RequestMapping(value = "sendredpack.do")
    @ResponseBody
    public void sendRedPack(HttpServletRequest req,HttpServletResponse resp,Map map) throws IOException {

       //开始发送红包
       System.out.println("红包发送开始");

       req.getInputStream();
       req.setCharacterEncoding("UTF-8");
       resp.setContentType("text/html;charset=utf-8");

       PrintWriter out = resp.getWriter();

       String message=null;

       try {
           String openId = map.get("FromUserName").toString();
           message = iSendRedPackService.sendRedPackSub(openId);
       } catch (Exception e) {
           logger.error("红包Controller异常",e);
       }
       out.print(message);

   }

}

 

ServiceImpl业务层

@Service("iSendRedPackService")
public class SendRedPackServiceImpl implements ISendRedPackService {

    public static final Logger logger = LoggerFactory.getLogger(SendRedPackServiceImpl.class);

    public static final String SENDREDPACK_URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";

    @Autowired
    private IUserService iUserService;


//String content

    public String sendRedPackSub(String openId) throws Exception {

        String respResult = null;

        //查询该用户是否关注公众号
        ServerResponse<JSONObject> response = iUserService.getUserInfo(openId);
        JSONObject jsonObject = response.getData();
        if(Integer.valueOf(jsonObject.get("subscribe").toString()) == Const.UserStatus.UN_SUBSCRIBE ){
            return respResult = "先关注后领取哦!";
        }

        SortedMap sortedMap = this.assembleSendRedPack(openId);
        String reuqestXml = SendRedPackUtil.getRequestXML(sortedMap);

        System.out.println(reuqestXml);

        String jsonStr = this.connect(reuqestXml);
        System.out.println(jsonStr);
        try {

            Document document = DocumentHelper.parseText(jsonStr);
            Element root = document.getRootElement();

            //只有当returnCode和resultCode都为SUCCESS时,红包才为发送成功
            String returnCode = root.element("return_code").getText();
            if (returnCode.equals("SUCCESS")) {
                String result_code = root.element("result_code").getText();
                GiveRedPack giveRedPack = null;
                if (result_code.equals("SUCCESS")) {

                    //自己的后续操作
                    return respResult = "红包领取成功,注意查收!";
                }
                return respResult = "怎么没领到呢,再来一次!";
            }
        } catch (Exception e) {
            logger.error("document数据读取异常", e);
        }
        return null;
    }

    private String connect(String reuqestXml){
        FileInputStream instream = null;
        BasicHttpClientConnectionManager connManager;
        try {

            String apiUrl= "//var//tomcat//tomcat-7//webapps//mdspirit//WEB-INF//classes//cert//wxpay//yichen_cert.p12";

            File file = new File(apiUrl);
            instream = new FileInputStream(file);
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            keyStore.load(instream, PropertiesUtil.getProperty("mch_id").toCharArray());

            // 实例化密钥库 & 初始化密钥工厂
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(keyStore, PropertiesUtil.getProperty("mch_id").toCharArray());

            // 创建 SSLContext
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());

            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
                    sslContext,
                    new String[]{"TLSv1"},
                    null,
                    new DefaultHostnameVerifier());

            connManager = new BasicHttpClientConnectionManager(
                    RegistryBuilder.<ConnectionSocketFactory>create()
                            .register("http", PlainConnectionSocketFactory.getSocketFactory())
                            .register("https", sslConnectionSocketFactory)
                            .build(),
                    null,
                    null,
                    null
            );

            HttpClient httpClient = null;
            try{

                httpClient = HttpClientBuilder.create()
                        .setConnectionManager(connManager)
                        .build();
                HttpPost httpPost = new HttpPost(SENDREDPACK_URL);
                StringEntity postEntity = new StringEntity(new String(reuqestXml.getBytes(), "UTF-8"));
                httpPost.addHeader("Content-Type", "text/xml");
                httpPost.addHeader("User-Agent", USER_AGENT + " " + PropertiesUtil.getProperty("mch_id"));
                httpPost.setEntity(postEntity);

                HttpResponse httpResponse = httpClient.execute(httpPost);
                HttpEntity httpEntity = httpResponse.getEntity();

                return EntityUtils.toString(httpEntity, "utf-8");

            }catch (Exception e){
                logger.error("红包发送连接错误",e);
            }finally {
                connManager.close();
                ((CloseableHttpClient) httpClient).close();
            }

        }catch (Exception e){
            logger.error("红包链接初始化错误",e);
        }finally {
            try {
                instream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    private SortedMap assembleSendRedPack(String openId) throws Exception{
        SortedMap sortedMap = new TreeMap();
        sortedMap.put("nonce_str", UUIDUtil.getUUId(PropertiesUtil.getProperty("mch_id")));  //随机字符串生成
        sortedMap.put("mch_billno", String.valueOf(generateOrderNo()));                //商户订单号生成,唯一
        sortedMap.put("mch_id", PropertiesUtil.getProperty("mch_id"));                 //商户号,微信支付分配的商户号,请不要填写APPID号
//        sortedMap.put("sub_mch_id", PropertiesUtil.getProperty("sub_mch_id"));         //子商户号
        sortedMap.put("wxappid", PropertiesUtil.getProperty("wxappid"));               //代理商公众号
//        sortedMap.put("msgappid", PropertiesUtil.getProperty("msgappid"));             //子商户公众号
        sortedMap.put("send_name", PropertiesUtil.getProperty("send_name"));           //商户名称
        sortedMap.put("re_openid", openId);                                            //用户openid

//         List<RedPackType> redPackTypeList = iRedPackTypeService.selectAll().getData();
//        RedPackType redPackType = SendRedPackUtil.getPercent(redPackTypeList);
//        sortedMap.put("total_amount", BigDecimalUtil.mul(Double.valueOf(redPackType.getAmount().intValue()),Double.valueOf(100)));
        sortedMap.put("total_amount", PropertiesUtil.getProperty("total_amount"));
        sortedMap.put("total_num", PropertiesUtil.getProperty("total_num"));
        sortedMap.put("wishing", PropertiesUtil.getProperty("wishing"));
        sortedMap.put("client_ip", PropertiesUtil.getProperty("client_ip"));
        sortedMap.put("act_name", PropertiesUtil.getProperty("act_name"));
        sortedMap.put("remark", PropertiesUtil.getProperty("remark"));
        Integer totalAmount = Integer.valueOf(sortedMap.get("total_amount").toString());
        if(totalAmount > 20000){
            sortedMap.put("scene_id", Const.SendRedPackSceneIdEnum.PRODUCT_1.getCode());      //用户场景id,红包金额不在普通红包范围内为必填
        }
        String sign = SendRedPackUtil.generateSignature(sortedMap,SendRedPackUtil.SignType.MD5);
        sortedMap.put("sign", sign);
        return sortedMap;
    }

    private long generateOrderNo(){
        long currentTime =System.currentTimeMillis();
        return currentTime+new Random().nextInt(100);
    }

主要的工具类:

public class SendRedPackUtil {

    public static final String FIELD_SIGN = "sign";

    public enum SignType {
        MD5, HMACSHA256
    }

    public static String createMD5Sign(SortedMap pmap){
        StringBuilder sb = new StringBuilder();
        String stringA = "";

        Iterator<Map.Entry<String, Object>> entries = pmap.entrySet().iterator();

        while (entries.hasNext()) {

            Map.Entry<String, Object> entry = entries.next();
            stringA += ((entry.getValue() == null || entry.getValue().equals("")) ? stringA + "" : stringA + "Key = " + entry.getKey() + "&Value = " + entry.getValue());
        }

        //拼接,key为商户平台设置的密钥key
        String stringSignTemp = stringA + PropertiesUtil.getProperty("api_key");
        String sign= MD5Util.MD5Encode(stringSignTemp,"utf-8").toUpperCase();
        return sign;

    }


    public static String getRequestXML(Map<String,String> map)throws Exception{
        StringBuilder sb = new StringBuilder("<xml>");
        for(Map.Entry<String,String> en:map.entrySet()){
            String key = en.getKey();
            sb.append("<"+key+"><![CDATA[");
            sb.append(en.getValue());
            sb.append("]]></"+key+">");
        }
        return sb.append("</xml>").toString();
    }

    /**
     * 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
     *
     * @param data 待签名数据
     * @param signType 签名方式
     * @return 签名
     */
    public static String generateSignature(final Map<String, String> data,SignType signType) 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) {
            if (k.equals(FIELD_SIGN)) {
                continue;
            }
            if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
                sb.append(k).append("=").append(data.get(k).trim()).append("&");
        }
        sb.append("key=").append(PropertiesUtil.getProperty("api_key"));
        if (SignType.MD5.equals(signType)) {
            return MD5(sb.toString()).toUpperCase();
        }
        else {
            throw new Exception(String.format("Invalid sign_type: %s", signType));
        }
    }


    /**
     * 生成 MD5
     *
     * @param data 待处理数据
     * @return MD5结果
     */
    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();
    }


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值