微信公众号开发-消息的接收与回复(文本)

微信公众号开发-消息的接收与回复(文本)

这一期我们主要讲一下,服务号的文本消息接收与被动回复。

首先我们看一下微信给出的api
在这里插入图片描述在这里插入图片描述
官方文档给出的api中有那么几个重要信息,第一个微信是将手机发送给微信服务号的消息,以Xml 的形式又以Post 的请求方式下发给我的自己填写的URL上。
画个图好理解一下
在这里插入图片描述
那么有了这几个内容,我们就很容易获取文本消息了。

话不多说,直接上代码讲思路

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;

/**
 * @fileName:EventController
 * @author:18013
 * @createTime:2019-05-24:15:23
 */
@RestController
@RequestMapping("/weixin")
public class EventController {

    @Autowired
    EventService eventService;

    /**
     * 微信服务器下发的消息
     * @param request
     * @return
     */
    @PostMapping("/validate")
    public String weixinConnect(HttpServletRequest request) throws IllegalAccessException, InstantiationException {
    	//用来接收微信下发的xml信息
        BufferedReader bufferedReader = null;
        StringBuffer stringBuffer =null;
        String str;
        try {
            bufferedReader = request.getReader();
            stringBuffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                stringBuffer.append(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(bufferedReader!=null){
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

   		//userInfo 用户信息(xml)
        String userInfo = stringBuffer.toString();
		if(userInfo.contains("Content")){
			// 解析xml,根据文本内容,业务逻辑,回复相应的消息给用户
            final String replyContentMsg = eventService.replyContentMsg(userInfo);
            System.out.println(replyContentMsg);
            return replyContentMsg;
        }
        return "";
    }
}

在回复消息前,我们需要解析xml,获取里面文本内容,openid等。
这边由于微信发送的xml ,格式十分相似,所以我建了一个基础消息model,其他用以继承便可。


import lombok.Data;
/**
 * @fileName:BaseWxModel 
 * @author:ccl
 * @createTime:2019-05-29:13:39
 */
@Data
public class BaseWxModel {
    private String toUserName; //开发者微信号
    private String fromUserName;//	发送方帐号(一个OpenID)
    private String createTime;//	消息创建时间 (整型)
    private String msgType;//	消息类型,event
    private String msgId; //用于排查
}

下面贴这期关键 文本消息的bean

import lombok.Data;

/**
 * @fileName:ContentMsg
 * @author:ccl
 * @createTime:2019-05-29:13:49
 */
@Data
public class ContentMsg extends BaseWxModel{
    private String content;//文本
}

有了这个模型 我们可以进行xml的解析了,这里我用的是反射思想。

    /**
     * 解析收到的消息
     * @param message
     * @return
     */
    public ContentMsg receiveContentMsg(String message){
        ContentMsg contentMsg = new ContentMsg();
        // 遍历类
        for (Class clazz = contentMsg.getClass();!clazz.equals(Object.class);clazz=clazz.getSuperclass()){
            Field fields[] = clazz.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                String column = field.getName();
                //获取属性值
                String colunmValue = XmlUtils.getColunmValue(message, column.toUpperCase().substring(0, 1) + column.substring(1));
                if (EmptyUtils.isNotEmpty(colunmValue)) {
                    try {
                        Method method = clazz.getDeclaredMethod("set" + column.toUpperCase().substring(0, 1) + column.substring(1), String.class);
                        method.invoke(contentMsg, colunmValue);
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        log.info("收到消息:{}",contentMsg.getContent());
        return contentMsg;
    }

下面再贴两个我写的工具类

大家先看我的getColunmValue 方法 ,这个xml解析是我根据微信回复内容格式基本一致。取巧写出来的。很简单方便,
因为标签包裹的只有两种形式, < column ><![CDATA[columnValue]]></ column> 和 < column>< columnValue ></ column> 这两种。
parseToXml 是根据反射思想写的,大家要是不懂的话,可以留言问我 或者直接联系我。

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @fileName:XmlUtils
 * @author:ccl
 * @createTime:2019-05-24:15:33
 */
public class XmlUtils {
    /**
     * 获取xml中相应的字段名
     * @param str
     * @return
     */
    public static String getColunmValue(String str, String column) {
        String beginStr = "<" + column + "><![CDATA[";
        String endStr = "]]></" + column + ">";
        int i = str.indexOf(beginStr);
        int i2 = str.indexOf(endStr);
        if (i < 0) {
            beginStr = "<" + column + ">";
            endStr = "</" + column + ">";
            i = str.indexOf(beginStr);
            i2 = str.indexOf(endStr);
            if (i < 0) {
                return null;
            }
        }
        return str.substring(i + beginStr.length(), i2);
    }

    public static String parseToXml(Object o) throws IllegalAccessException, InstantiationException {
        StringBuffer stringBuffer = new StringBuffer();
        Method method;
        stringBuffer.append("<xml>");
        for (Class clazz = o.getClass();!clazz.equals(Object.class);clazz=clazz.getSuperclass()){
            Field fields[] = clazz.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                String column = field.getName();
                if(EmptyUtils.isNotEmpty(field.get(o))){
                    try {
                         method= clazz.getDeclaredMethod("get" + column.toUpperCase().substring(0, 1) + column.substring(1));
                        if (!method.getName().equals("getMsgId")){
                            String result = (String) method.invoke(o);
                            stringBuffer.append("<"+method.getName().substring(3)+">");
                            if (!method.getName().equals("getCreateTime")){
                                stringBuffer.append("<![CDATA["+result+"]]></"+ method.getName().substring(3)+">");
                            }else {
                                stringBuffer.append(result+"</"+ method.getName().substring(3)+">");
                            }
                        }
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        stringBuffer.append("</xml>");
        return  stringBuffer.toString();
    }
}

下面贴EmptyUtils


import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Map;

public class EmptyUtils {

    /**
     * 判断对象是否为空
     *
     * @param obj 对象
     * @return {@code true}: 为空<br>{@code false}: 不为空
     */
    public static boolean isEmpty(Object obj) {
        //判断对象是否为null
        if (obj == null) {
            return true;
        }
        //判断String类型对象是否为空
        if (obj instanceof String && obj.toString().length() == 0) {
            return true;
        }
        //判断数组对象是否为空
        if (obj.getClass().isArray() && Array.getLength(obj) == 0) {
            return true;
        }
        //判断集合对象是否为空
        if (obj instanceof Collection && ((Collection) obj).isEmpty()) {
            return true;
        }
        //判断Map对象是否为空
        if (obj instanceof Map && ((Map) obj).isEmpty()) {
            return true;
        }
        return false;
    }

    /**
     * 判断对象是否非空
     *
     * @param obj 对象
     * @return {@code true}: 非空<br>{@code false}: 空
     */
    public static boolean isNotEmpty(Object obj) {
        return !isEmpty(obj);
    }
}

获取到了文本值和openid等其他关键信息后,我们可以正式开始回复了。

下面贴回复代码

   public String replyContentMsg(String message) throws InstantiationException, IllegalAccessException {
        ContentMsg contentMsg = receiveContentMsg(message);
        final String receiveContentMsg = contentMsg.getContent();
        if (receiveContentMsg.equals("我的openid")){
            //回复内容 比方说获取自己的openid
            contentMsg.setContent(contentMsg.getFromUserName());

        }else{
            contentMsg.setContent("我也不知道回什么好");
        }
        //注意 这边的 FromUserName 和 ToUserName 需要对调一下 因为现在是服务器发送给用户了
        String temp =  contentMsg.getFromUserName();
        contentMsg.setFromUserName(contentMsg.getToUserName());
        contentMsg.setToUserName(temp);
        contentMsg.setMsgType("text");
        contentMsg.setCreateTime(new Date().getTime()+"");
        return XmlUtils.parseToXml(contentMsg);
    }

}

效果展示
在这里插入图片描述

这样我们的消息回复就算完成了,其实可以写的简单 不需要建基础模型和反射做个简单的例子照样可以完成,但是我还是希望同学们能多学到一点。希望我们可以一起进步,因为我也只是个刚刚开始起步的年轻人。(想找个好工作hhh)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值