微信小程序爬坑日记(二) -- JAVA客服消息自动回复

背景说明 :用户在小程序内点击按钮,打开客服对话界面,自动发送活动二维码或根据关键词自动回复

第一步去微信公众平台开启客服自动回复功能

微信小程序爬坑日记(二) -- JAVA客服消息自动回复_第1张图片
微信小程序爬坑日记(二) -- JAVA客服消息自动回复_第2张图片

第二步查阅官方文档,找到小程序客服API文档[链接如下]https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/customer-message/customerServiceMessage.send.html

根据文档描述,发送图片需要临时素材的form_id,所以首先得完成临时素材的上传获取到form_id

临时素材上传代码
    /**
     * 微信小程序临时素材上传
     *
     * @param file
     * @return
     * @author 13
     * @throws Exception
     */
    public String uploadFile(MultipartFile file) throws Exception {
        String url = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=" + ACCESS_TOKEN + "&type=image";
        String result = null;
        String fileName = file.getOriginalFilename();
        URL urlObj = new URL(url);
        HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();
        con.setRequestMethod("POST");
        con.setDoInput(true);
        con.setDoOutput(true);
        con.setUseCaches(false);
        // 设置请求头信息
        con.setRequestProperty("Connection", "Keep-Alive");
        con.setRequestProperty("Charset", "UTF-8");
        // 设置边界
        String BOUNDARY = "----------" + System.currentTimeMillis();
        con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
        // 请求正文信息
        // 第一部分:
        StringBuilder sb = new StringBuilder();
        sb.append("--"); // 必须多两道线
        sb.append(BOUNDARY);
        sb.append("\r\n");
        sb.append("Content-Disposition: form-data;name=\"media\";filename=\"" + fileName + "\"\r\n");
        sb.append("Content-Type:application/octet-stream\r\n\r\n");
        byte[] head = sb.toString().getBytes("utf-8");
        // 获得输出流
        OutputStream out = new DataOutputStream(con.getOutputStream());
        // 输出表头
        out.write(head);
        // 文件正文部分
        // 把文件已流文件的方式 推入到url中
        DataInputStream in = new DataInputStream(file.getInputStream());
        int bytes = 0;
        byte[] bufferOut = new byte[1024];
        while ((bytes = in.read(bufferOut)) != -1) {
            out.write(bufferOut, 0, bytes);
        }
        in.close();
        // 结尾部分
        byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
        out.write(foot);
        out.flush();
        out.close();
        StringBuffer buffer = new StringBuffer();
        BufferedReader reader = null;
        try {
            // 定义BufferedReader输入流来读取URL的响应
            reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            if (result == null) {
                result = buffer.toString();
            }
        } catch (IOException e) {
            System.out.println("发送POST请求出现异常! {}");
            e.printStackTrace();
            throw new IOException("数据读取异常");
        } finally {
            if (reader != null) {
                reader.close();
            }
        }
        // 获取到返回HTTP结果
        Map<String, Object> map = JSONObject.parseObject(result, Map.class);
        if (map.containsKey("media_id")) {
            return map.get("media_id").toString();
        }
        System.out.println("小程序上传临时素材出错,返回信息为:    " + result);
        return null;
    }

拿到form_id以后就可以进行客服消息自动回复了

第三步,自动回复接口编写

同一个接口,设置服务器地址微信会进行get请求校验服务器地址的可用性,而post接口则进行客服消息自动回复

    //  开启时填写的秘钥
    private static final String token="XXXXXXXX";
    /**
     * 微信小程序消息验证和配置
     *
     * @author 13
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/message", method = RequestMethod.GET)
    public String getProcess(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 微信加密签名
        String signature = request.getParameter("signature");
        // 时间戳
        String timestamp = request.getParameter("timestamp");
        // 随机数
        String nonce = request.getParameter("nonce");
        // 随机字符串
        String echostr = request.getParameter("echostr");
        // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
        if (this.checkSignature(signature, timestamp, nonce)) {
            return echostr;
        }
        return null;
    }
	  /**
     * 微信小程序客服消息自动回复
     *
     * @author 13
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/message", method = RequestMethod.POST)
    public String replyMessage(@RequestBody Map<String, Object> msg, HttpServletRequest request, HttpServletResponse response) throws Exception {
        return appletCommonService.replyMessage(msg);
    }

    private  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 (Exception e) {
            e.printStackTrace();
        }
        content = null;
        // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    }
    /**
     * 将字节数组转换为十六进制字符串
     * @author 13
     * @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;
    }
    /**
     * 将字节转换为十六进制字符串
     * @author 13
     * @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;
    }


以下代码是消息回复代码
@Service
public class AppletCommonService {

    public static final String[] keyWord = {"你好", "您好", "请问", "在"};
    public static final List<String> keyList = Arrays.asList(keyWord);
    //	小程序的access_token
    public static final String ACCESS_TOKEN = "";

    /**
     * 小程序客服自动回复功能
     *	@author 13
     * @param msg 微信传递的参数集合
     * @return "SUCCEE"告知微信处理成功
     * @throws Exception
     */
    public String replyMessage(Map<String, Object> msg) throws Exception {
        System.out.println("客服消息自动回复 ====> start");
        String opendId = msg.get("FromUserName").toString();
        Map<String, String> contenMap = new HashMap<String, String>();
        // 发送结果
        String result = "";
        String conten = msg.get("Content") == null ? "" : msg.get("Content").toString();
        //  判断文字中是否包含关键词,若包含则提前自动回复
        boolean flag = false;
        for (String string : keyList) {
            if (conten.startsWith(string)) {
                flag = true;
                break;
            }
        }
        // 若用户消息包含关键字则自动回复
        if (flag) {
            contenMap.put("content", "你好!正在赶来的路上,可以先留下你的问题");
            result = sendMessage(opendId, "text", contenMap);
            System.out.println("客服自动回复结果:" + result);
            // 此处将消息转发至人工客服,不然人工客服窗会没有消息
            Map<String, Object> tranMap = new HashMap<String, Object>();
            tranMap.put("ToUserName", msg.get("FromUserName"));
            tranMap.put("FromUserName", msg.get("ToUserName"));
            tranMap.put("CreateTime", msg.get("CreateTime"));
            tranMap.put("MsgType", "transfer_customer_service");
            String messageJson = JSONObject.toJSONString(tranMap);
            System.out.println("消息转发至人工客服");
            return messageJson;
        }
        //	TODO 此处根据自己的业务逻辑获取微信临时素材id
        String mediaId = "xxxxxxxx";
        //	若没有活动临时素材则不进项操作
        if (StringUtils.isBlank(mediaId)) {
            // 此处将消息转发至人工客服,不然人工客服窗会没有消息
            Map<String, Object> tranMap = new HashMap<String, Object>();
            tranMap.put("ToUserName", msg.get("FromUserName"));
            tranMap.put("FromUserName", msg.get("ToUserName"));
            tranMap.put("CreateTime", msg.get("CreateTime"));
            tranMap.put("MsgType", "transfer_customer_service");
            String messageJson = JSONObject.toJSONString(tranMap);
            System.out.println("消息转发至人工客服");
            return messageJson;
        }
        //  有临时素材照片则自动回复临时素材图片media_id【 活动二维码或推广二维码等】
        contenMap.put("media_id", mediaId);
        result = sendMessage(opendId, "image", contenMap);
        System.out.println("客服自动回复结果:" + result);
        return "SUCCESS";
    }

    /**
     * 客服消息自动回复
     * @author 13
     * @param opendId    接收者openId
     * @param msgtype    消息格式:text 文本;image 图片; link 图文链接
     * @param contentMap 正文map
     * @return
     * @throws UnsupportedEncodingException
     */
    private String sendMessage(String opendId, String msgtype, Map<String, String> contentMap) throws UnsupportedEncodingException {
        Map<String, Object> replyMessageMap = new HashMap<String, Object>();
        replyMessageMap.put("touser", opendId);
        replyMessageMap.put("msgtype", msgtype);
        replyMessageMap.put(msgtype, contentMap);
        String messageJson = JSONObject.toJSONString(replyMessageMap);
        messageJson = new String(messageJson.getBytes(), "UTF-8");
        String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + ACCESS_TOKEN;
        // 发送结果
        return HttpUtils.sendPost(url, messageJson);
    }

   }

代码中用到的HttpUtils是自己写的,可以网上随便搜下怎么发post请求即可

以上便是小程序微信客服消息自动回复所有事项了

你可能感兴趣的:(微信小程序爬坑日记(二) -- JAVA客服消息自动回复)