微信公众号JAVA后台对接最全面

微信公众号JAVA后台对接最全面
微信公众号JAVA后台对接步骤

1.环境搭建

     (1)接口测试号申请

                拿到appid和appsecret,配置在后台配置文件!

                https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index

2.代码编写

    公众号接口配置信息的填写,必须直接填写到指定的方法中,填写完,微信服务器会立即请求到填写服务器的地址,进行验证。

  在微信公众号中,不管是验证服务器安全性还是微信消息推送,都只会走这个接口。一般情况下,验证安全性是get请求,而消息推送等都是POST请求,并且数据格式为XML,所以这个方法,就大有来头.

(1)获取消息推送

POM插件

<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.4.10</version>
</dependency>



    @RequestMapping(value = "/get")
    public void msgIn(HttpServletResponse response, HttpServletRequest request) throws ServletException, IOException {
        if ("GET".equals(request.getMethod())) {
            bindMsg(response, request);
        } else if ("POST".equals(request.getMethod())) {
            System.out.println("走的是post");
            doPost(request, response);
        }
    }


 

/**
     * 微信公共号get请求,服务器安全性校验。
     * @param response
     * @param request
     */
    public void bindMsg(HttpServletResponse response, HttpServletRequest request) {

        String echostr = request.getParameter("echostr");

        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        try {
            if (SignUtil.checkSignature(signature, timestamp, nonce)) {
                PrintWriter out = response.getWriter();
                out.print(echostr);
                out.close();
            } else {
                logger.info("这里存在非法请求!");
            }

        } catch (Exception e) {
            logger.error(e.toString());
        }


    }


/**
     * 接收并处理微信客户端发送的请求
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        request.setCharacterEncoding("utf-8");
        response.setContentType("text/xml;charset=utf-8");

        PrintWriter out = response.getWriter();
        try {
            // 拿到微信客户端发来的请求并通过工具类解析为map格式
            Map<String, String> map = XmlUtilMap.xmlToMap(request);
            String toUserName = map.get("ToUserName");
            String fromUserName = map.get("FromUserName");  //openid
            String msgType = map.get("MsgType");
            String content = map.get("Content");
            String event = map.get("event");
            System.out.println(fromUserName);
            if (event.equals("subscribe")) {
                System.out.println("用户关注了微信公众号, 这里写自己的业务逻辑.....");
            }

            if (event.equals("unsubscribe")) {
                logger.info("用户取消关注公众号, 这里写自己的业务逻辑......");
                System.out.println("用户取消关注公众号, 这里写自己的业务逻辑......");
            }


        } catch (Exception E) {
            E.getMessage();
        }
    }

工具类***********

public class SignUtil {

    // 与接口配置信息中的 Token 要一致
    private static String token = "gede";
    /**
     * 验证签名
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static boolean checkSignature(String signature, String timestamp, String nonce) {
        String[] arr = new String[] { token, timestamp, nonce };
        // 将 token、timestamp、nonce 三个参数进行字典序排序
        Arrays.sort(arr);
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
        MessageDigest md = null;
        String tmpStr = null;

        try {
            md = MessageDigest.getInstance("SHA-1");
            // 将三个参数字符串拼接成一个字符串进行 sha1 加密
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        content = null;
        // 将 sha1 加密后的字符串可与 signature 对比,标识该请求来源于微信
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    }

    /**
     * 将字节数组转换为十六进制字符串
     * @param byteArray
     * @return
     */
    private static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }

    /**
     * 将字节转换为十六进制字符串
     * @param mByte
     * @return
     */
    private static String byteToHexStr(byte mByte) {
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];
        String s = new String(tempArr);
        return s;
    }
}

/**
 * 实现消息的格式转换(Map类型和XML的互转)
 */
public class XmlUtilMap {
    /**
     * 将XML转换成Map集合
     */
    public static Map<String, String> xmlToMap(HttpServletRequest request)
            throws IOException, DocumentException {

        Map<String, String> map = new HashMap<String, String>();
        SAXReader reader = new SAXReader(); // 使用dom4j解析xml
        InputStream is= request.getInputStream(); // 从request中获取输入流
        Document doc = reader.read(is);

        Element root = doc.getRootElement(); // 获取根元素
        List<Element> list = root.elements(); // 获取所有节点

        for (Element e : list) {
            map.put(e.getName(), e.getText());
            System.out.println(e.getName() + "--->" + e.getText());
        }
        is.close();
        return map;
    }

    /**
     * 将文本消息对象转换成XML
     */
    public static String textMessageToXML(WechatNotifyRequestVO textMessage) {
        XStream xstream = new XStream(); // 使用XStream将实体类的实例转换成xml格式
        System.out.println(",,,,,,,,,,");
        xstream.alias("xml", textMessage.getClass()); // 将xml的默认根节点替换成“xml”
        System.out.println("......");
        return xstream.toXML(textMessage);
    }
}

实体类,封装微信传递的参数。

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
public class WechatNotifyRequestVO {

    @ApiModelProperty("开发者微信号")

    private String toUserName;

    @ApiModelProperty("发送方帐号(一个OpenID)")

    private String fromUserName;

    @ApiModelProperty("消息创建时间 (整型)")

    private Integer createTime;

    @ApiModelProperty("消息类型,event")

    private String messageType;

    @ApiModelProperty("事件类型,subscribe(订阅)、unsubscribe(取消订阅)")

    private String event;
}

(2)发送模板消息

         要给用户发送模板消息,最最主要的是拿到opeind!!!!

     步揍:a:在微信公众号创建消息模板,拿到模板id。请注意每个字段后面必须有DATA

              如下:尊敬的【{{fist.DATA}}】,您的计量仪器检校异常,请您及时处理。

					 仪器名称: {{keyword1.DATA}} 

					规格型号:{{keyword2.DATA}} 

					出厂编号:{{keyword3.DATA}}

					业务员:{{keyword4.DATA}} 

						备注:{{keyword5.DATA}} 

              b:获取TOKEN,token有效期为2个小时。本示列代码使用的redis,存储时间为119分钟。在需要使用token的时候,可以从rendis中获取,若redis中没有,可调用下列方法生成新的redis。

               

/**
 * 获取token
 *
 * @return token
 */
public  String getToken() {
    // 授予形式
    String grant_type = "client_credential";
    // 接口地址拼接参数
    String getTokenApi = "https://api.weixin.qq.com/cgi-bin/token?grant_type=" + grant_type + "&appid=" + appid
            + "&secret=" + secret;
    String tokenJsonStr = sendGet(getTokenApi);
    JSONObject tokenJson = JSONObject.parseObject(tokenJsonStr);
    String token = tokenJson.get("access_token").toString();
    redisTemplate.opsForValue().set("token", token, 119, TimeUnit.MINUTES);
    System.out.println("获取到的TOKEN : " + token);
    return token;
}

  工具类:



/**
 * HTTP/get
 * @param requestUrl
 * @return
 */

public static String sendGet(String requestUrl) {
    StringBuffer buffer = null;

    try {
        // 建立连接
        URL url = new URL(requestUrl);
        HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();
        httpUrlConn.setDoInput(true);
        httpUrlConn.setRequestMethod("GET");

        // 获取输入流
        InputStream inputStream = httpUrlConn.getInputStream();
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

        // 读取返回结果
        buffer = new StringBuffer();
        String str = null;
        while ((str = bufferedReader.readLine()) != null) {
            buffer.append(str);
        }

        // 释放资源
        bufferedReader.close();
        inputStreamReader.close();
        inputStream.close();
        httpUrlConn.disconnect();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return buffer.toString();
}

c: 消息推送

(因为一次只能调用方法推送一次,所以可以传多个手机号,循环调用推送方法)

/**
 * 推送测试
 * http://localhost:8082/api/subscription/a
 */
@RequestMapping("/a")
@ResponseBody
public void  test(){
    List<String> phone = new ArrayList<>();
    phone.add("18792460893");      //此条数据对应的openid已经维护进wechat_fan表
    //仪器校验测试
    CompleteParam completeParam = new CompleteParam();
    completeParam.setCustomerName("西安测试公司");
    completeParam.setOrderSerila("111111-9898");
    completeParam.setPrice("100");
    completeParam.setNumber("11");
    completeParam.setCompletedata("2020-3-15");
    completeParam.setPhone(phone);
    complete(completeParam);

}

/**
 *仪器校验完成消息推送
 * @param completeParam
 */
public void complete(CompleteParam completeParam) {
  Map<String, Object> dataMap = new HashMap<String, Object>();
    //根据自己的模板定义内容和颜色
    DataWx dataWx1 = new DataWx();
    dataWx1.setValue(completeParam.getCustomerName());
    dataWx1.setColor("#173177");
    DataWx dataWx2 = new DataWx();
    dataWx2.setValue(completeParam.getOrderSerila());
    dataWx2.setColor("#173177");
    DataWx dataWx3 = new DataWx();
    dataWx3.setValue(completeParam.getPrice());
    dataWx3.setColor("#173177");
    DataWx dataWx4 = new DataWx();
    dataWx4.setValue(completeParam.getNumber());
    dataWx4.setColor("#173177");
    DataWx dataWx5 = new DataWx();
    dataWx5.setValue(completeParam.getCompletedata());
    dataWx5.setColor("#173177");
    dataMap.put("fist",dataWx1);
    dataMap.put("keyword1",dataWx2);
    dataMap.put("keyword2",dataWx3);
    dataMap.put("keyword3",dataWx4);
    dataMap.put("keyword4",dataWx5);
    List<String> phone = completeParam.getPhone();
    if (StringUtils.isNotEmpty(phone)){
        //整体参数map
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("template_id", templateId_complete);
        paramMap.put("data", dataMap);
        paramMap.put("url", "https://www.baidu.com");  //跳转其他路径

    if (phone.size()==1){
       WeChartFan weChartFan = weChartFanService.findUniqueByProperty("phone", phone.get(0));

        if (StringUtils.isNotEmpty(weChartFan)){
            paramMap.put("touser", weChartFan.getOpenId());
            SendWeChatMsg(paramMap);
        }
    }else {
        for (String s : phone) {
            WeChartFan weChartFan = weChartFanService.findByPhone(phone.get(0));
            if (StringUtils.isNotEmpty(weChartFan)){
                paramMap.put("touser", weChartFan.getOpenId());
                SendWeChatMsg(paramMap);
            }


        }
    }

    }


}

/**
 * 公众号消息推送请求公共api
 * @param map
 */
public void SendWeChatMsg(Map<String, Object> map) {
    String token;
    Object token1 = redisTemplate.opsForValue().get("token");
    if (StringUtils.isNotEmpty(token1)){
        token = token1.toString();
        System.out.println("从redis中拿取的:"+token);
    }else {
        token = wxConfig.getToken();
        System.out.println("重新生成的token:"+token);
    }
    // 接口地址
    String sendMsgApi = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+token;
    System.out.println(WxConfig.sendpost(sendMsgApi,map));
}

/**
 * 调用接口 http/POST
 * @param apiPath
 */
public static String sendpost(String apiPath,Map<String,Object> paramMap){
    OutputStreamWriter out = null;
    InputStream is = null;
    String result = null;
    try{
        URL url = new URL(apiPath);// 创建连接
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setUseCaches(false);
        connection.setInstanceFollowRedirects(true);
        connection.setRequestMethod("POST") ; // 设置请求方式
        connection.setRequestProperty("Charset", "UTF-8"); // 设置接收数据的格式
        connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); // 设置发送数据的格式
        connection.connect();
            out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); // utf-8编码
            out.append(JSON.toJSONString(paramMap));
            out.flush();
            out.close();
        // 读取响应
        BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(),"UTF-8"));
        String line;
        String responseStr="";
        while ((line = reader.readLine()) != null){
            responseStr+=line;
        }
        System.out.println(responseStr);
        reader.close();
        connection.disconnect();

    }catch (MalformedURLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ProtocolException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return "";
}
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

满头黑发到中年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值