微信公众号开发(二):利用责任链和模板方法模式设计消息的处理流程

由于微信服务器发送过来的消息分为文本消息、事件消息、图片消息、声音消息、链接消息、位置消息,处理不同的消息
需要不同的处理方式,但是基本流程差不多,所以我设计了一个处理链,不同的消息由不同的消息处理器来处理,达到可扩展性
和维护性的利好。设计一个处理消息的接口MessageHandler
/**
 * 处理消息的抽象接口,责任链模式
 * @author xsy
 *
 */
public interface MessageHandler {
    /**
     * 该你处理就处理消息的函数
     * @param requestMap
     * @return
     */
    public abstract BaseMessage handleMessage(Map<String, String> requestMap);
    /**
     * 设置你不能处理后续处理的对象
     * @param messageHandler
     */
    public abstract void setNextMessageHandler(MessageHandler nextMessageHandler);
}
其中handleMessage是消息处理器的核心方法,用于处理公众号的消息。requestMap用于封装接收到的消息的信息。
BaseMessage是一个JavaBean,是所有响应消息的基类。setNextMessageHandler用于设置下游处理器。
/**
* 消息基类(公众帐号-> 普通用户)
*
* @author 熊诗言
* @date 2015-09-05
*/
public class BaseMessage {
    // 接收方帐号(收到的OpenID)
    private String ToUserName;
    // 开发者微信号
    private String FromUserName;
    // 消息创建时间(整型)
    private long CreateTime;
    // 消息类型(text/music/news)
    private String MsgType;
    // 位0x0001 被标志时,星标刚收到的消息
    private int FuncFlag;
。。。。
}

又由于所有的处理器的基本处理流程是一致的,所以利用模板方法设计模式将基本的处理流程抽取形成DefaultMessageHandler,
子类的消息处理器只需要给出你能处理的消息的条件(canDo方法提供)和你的具体处理方法(handleByMe方法给出)即可。
以后要扩展自己的消息处理器只需要继承该类就行了。

public abstract class DefaultMessageHandler implements MessageHandler {

    protected MessageHandler nextMessageHandler;
    private MessageHandler finalMessageHandler;
    
    // 发送方帐号(open_id)
    protected String fromUserName ;
    // 公众帐号
    protected String toUserName ;

    public DefaultMessageHandler() {
        this.finalMessageHandler = FinalMessageHandler.sharedFinalMessageHandler();//默认的最终处理器,自己也可以通过setter方法改变
    }

    public void setFinalMessageHandler(MessageHandler finalMessageHandler) {
        this.finalMessageHandler = finalMessageHandler;
    }

    /**
     * 模板方法模式实现主要的逻辑,是自己处理还是交给下游处理
     */
    public BaseMessage handleMessage(Map<String, String> requestMap) {
        // 发送方帐号(open_id)
        fromUserName = requestMap.get("FromUserName");
        // 公众帐号
        toUserName = requestMap.get("ToUserName");
        if(canDo(requestMap)){
            /*try {
                return handleByMe(requestMap);
            } catch (Exception e) {
                e.printStackTrace();
                requestMap.put("error", e.fillInStackTrace().toString());
                return finalMessageHandler.handleMessage(requestMap);
            }*/
            return handleByMe(requestMap);
        }else {
            return nextMessageHandler.handleMessage(requestMap);
        }
    }
    
    public void setNextMessageHandler(MessageHandler nextMessageHandler) {
        this.nextMessageHandler = nextMessageHandler;
    }

    /**
     * 给出你处理的条件
     * @return
     */
    public abstract boolean canDo(Map<String, String> requestMap);
    /**
     * 你具体的处理
     * @param requestMap
     * @return
     */
    
    public abstract BaseMessage handleByMe(Map<String, String> requestMap);
}

FinalMessageHandler是最终的默认处理器,表示你的处理链处理不了了我的最终处理办法。由于全系统只需要一个这种处理器,所以设计成单例模式。
/**
 * 其他消息处理类处理不了的请求全部有这个类处理,返回一个失败信息
 * @author 熊诗言
 *
 */
public class FinalMessageHandler extends DefaultMessageHandler {

    private static final FinalMessageHandler _instance = new FinalMessageHandler();
    private FinalMessageHandler(){}
    public static FinalMessageHandler sharedFinalMessageHandler(){
        return _instance;
    }
    
    @Override
    public boolean canDo(Map<String, String> requestMap) {
        return true;
    }

    @Override
    public BaseMessage handleByMe(Map<String, String> requestMap) {
        return MessageFactory.createTextMessage(fromUserName, toUserName,
        "sorry,你发送的什么玩意儿,我处理不了,抱歉!!\n"+requestMap.get("error"));
    }

}

下面画一个UML图大体上表达一下意思:






有了以上的处理器之后,就可以构建我们的消息处理器链了
/**
* 核心服务类
*
* @author 熊诗言
* @date 2015-09-05
*/
public class WeiXinService {
    /**
    * 处理微信发来的请求,利用责任链模式和模板方法模式设计
    *
    * @param request
    * @return
    */
    public static String processRequest3(HttpServletRequest request) {
        BaseMessage message= null;
        try {
            // xml 请求解析
            Map<String, String> requestMap = MessageUtil.parseXml(request);
            
            //构造一个处理所有消息的链
            TextMessageHandler     textMessageHandler     = TextMessageHandler.sharedTextMessageHandler();
            EventMessageHandler    eventMessageHandler    = new EventMessageHandler();
            ImageMessageHandler    imageMessageHandler    = new ImageMessageHandler();
            VoiceMessageHandler    voiceMessageHandler    = new VoiceMessageHandler();
            LinkTextMessageHandler linkTextMessageHandler = new LinkTextMessageHandler();
            LocationMessageHandler locationMessageHandler = new LocationMessageHandler();
            FinalMessageHandler    finalMessageHandler    = FinalMessageHandler.sharedFinalMessageHandler();
            
            textMessageHandler.setNextMessageHandler(eventMessageHandler);
            eventMessageHandler.setNextMessageHandler(imageMessageHandler);
            imageMessageHandler.setNextMessageHandler(voiceMessageHandler);
            voiceMessageHandler.setNextMessageHandler(linkTextMessageHandler);
            linkTextMessageHandler.setNextMessageHandler(locationMessageHandler);
            locationMessageHandler.setNextMessageHandler(finalMessageHandler);
            
            message = textMessageHandler.handleMessage(requestMap);
            
            
        }catch (Exception e) {
            System.out.println(e);
        }
        return MessageUtil.messageToXml(message);
    }
    //对比以下的两种处理方式,很明显更优雅,具备更好的可维护性。
    /**
    * 处理微信发来的请求,系统架构更好了
    *
    * @param request
    * @return
    */
    @Deprecated
    public static String processRequest2(HttpServletRequest request) {
        BaseMessage message= null;
        try {
            // xml 请求解析
            Map<String, String> requestMap = MessageUtil.parseXml(request);
            
            //通过dispatchService分发给不同的service返回不同的消息
            message = DispatchService.dispatch(requestMap);
        }catch (Exception e) {
            System.out.println(e);
        }
        return MessageUtil.messageToXml(message);
    }
    /**
    * 处理微信发来的请求
    *
    * @param request
    * @return
    */
    @Deprecated
    public static String processRequest(HttpServletRequest request) {
        String respMessage = null;
        try {
            // 默认返回的文本消息内容
            String respContent = "功能还未开发,敬请期待!";
    
            // xml 请求解析
            Map<String, String> requestMap = MessageUtil.parseXml(request);
    
            // 发送方帐号(open_id)
            String fromUserName = requestMap.get("FromUserName");
            // 公众帐号
            String toUserName = requestMap.get("ToUserName");
            // 消息类型
            String msgType = requestMap.get("MsgType");
    
            // 回复文本消息
            TextMessage textMessage = new TextMessage();
            textMessage.setToUserName(fromUserName);
            textMessage.setFromUserName(toUserName);
            textMessage.setCreateTime(new Date().getTime());
            textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);
            textMessage.setFuncFlag(0);
    
            // 文本消息
            if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
                /**
                 * 以后在这里着墨应该是最多的,做聊天机器人啊 根据用户的回复关键词做相应的服务啊 比如实现音乐回复
                 */
                String content = requestMap.get("Content");
                if(ContentUtil.isQqFace(content)){
                    respContent = content;
                }else if("?".equals(content)){
                    respContent = ContentUtil.getMainTips();
                }else if("历史上的今天".equals(content)){
                    respContent = TodayInHistoryService.getTodayInHistoryInfo();
                }else if(content.startsWith("翻译")){
                    String keyWord = content.replaceFirst("^翻译", "");//真正需要翻译的东西
                    if ("".equals(keyWord)) {
                        respContent = ContentUtil.getTranslateUsage();//如果为空就返回提示
                    }else{
                        respContent = BaiduTranslateService.translate(keyWord);
                    }
                }else {
                    respContent = "您发送的是文本消息!自行车\ue136 男人\ue138 钱袋\ue12f 情侣\ue428 公共汽车\ue159";
                }
            }
            // 图片消息
            else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {
                respContent = "您发送的是图片消息!";
            }
            // 地理位置消息
            else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)){
                respContent = "您发送的是地理位置消息!";
            }
            // 链接消息
            else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) {
                respContent = "您发送的是链接消息!";
            }
            // 音频消息
            else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) {
                respContent = "您发送的是音频消息!";
            }
            // 事件推送
            else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {
                // 事件类型
                String eventType = requestMap.get("Event");
                // 订阅
                if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) {
                    respContent = ContentUtil.getMainTips();
                }
                // 取消订阅
                else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) {
                // TODO 取消订阅后用户再收不到公众号发送的消息,因此不需要回复消息
                }
                // 自定义菜单点击事件
                else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) {
                // TODO 自定义菜单权没有开放,暂不处理该类消息
                }
            }
    
            textMessage.setContent(respContent);
            respMessage = MessageUtil.textMessageToXml(textMessage);
        } catch (Exception e) {
            e.printStackTrace();
        }
    
        return respMessage;
    }
}




/**
 * 作为分派service,传过来不同的消息由不同的service做处理,以后设计成责任链模式
 * @author xsy
 *
 */
public class DispatchService {
    public static BaseMessage dispatch(Map<String, String> requestMap){
        BaseMessage message = null;
        // 发送方帐号(open_id)
        String fromUserName = requestMap.get("FromUserName");
        // 公众帐号
        String toUserName = requestMap.get("ToUserName");
        // 消息类型
        String msgType = requestMap.get("MsgType");
        // 文本消息
        if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
            /**
             * 以后在这里着墨应该是最多的,做聊天机器人啊 根据用户的回复关键词做相应的服务啊 比如实现音乐回复
             */
            String content = requestMap.get("Content").trim();
            if(ContentUtil.isQqFace(content)){
                message = MessageFactory.createTextMessage(fromUserName, toUserName,content);
            }else if("?".equals(content)){
                message = MessageFactory.createTextMessage(fromUserName, toUserName, ContentUtil.getMainTips());
            }else if("历史上的今天".equals(content)){
                message = MessageFactory.createTextMessage(fromUserName, toUserName, TodayInHistoryService.getTodayInHistoryInfo());
            }else if(content.startsWith("翻译")){
                String keyWord = content.replaceFirst("^翻译", "");//真正需要翻译的东西
                if ("".equals(keyWord)) {
                    message = MessageFactory.createTextMessage(fromUserName, toUserName, ContentUtil.getTranslateUsage());//如果为空就返回提示
                }else{
                    message = MessageFactory.createTextMessage(fromUserName, toUserName, BaiduTranslateService.translate(keyWord));
                }
            }else if(content.startsWith("歌曲")){
                // 将歌曲2 个字及歌曲后面的+、空格、-等特殊符号去掉
                String keyWord = content.replaceAll("^歌曲[\\+ ~!@#%^-_=]?", "");
                // 如果歌曲名称为空
                if ("".equals(keyWord)) {
                    message = MessageFactory.createTextMessage(fromUserName, toUserName, ContentUtil.getMusicUsage());
                } else {
                    String[] kwArr = keyWord.split("@");
                    // 歌曲名称
                    String musicTitle = kwArr[0];
                    // 演唱者默认为空
                    String musicAuthor = "";
                    if (2 == kwArr.length)
                        musicAuthor = kwArr[1];
                        // 搜索音乐
                        Music music = BaiduMusicService.searchMusic(musicTitle, musicAuthor);
                        // 未搜索到音乐
                        if (null == music) {
                            message = MessageFactory.createTextMessage(fromUserName, toUserName,
                                "对不起,没有找到你想听的歌曲<" + musicTitle + ">。");
                        } else {
                            message = MessageFactory.createMusicMessage(fromUserName, toUserName, music);
                        }
                    }
            }else {//作为最终的聊天机器人
                message = MessageFactory.createTextMessage(fromUserName, toUserName,
                        "您发送的是文本消息!自行车\ue136 男人\ue138 钱袋\ue12f 情侣\ue428 公共汽车\ue159");
            }
        }
        // 图片消息
        else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {
            message = MessageFactory.createTextMessage(fromUserName, toUserName,"您发送的是图片消息!");
        }
        // 地理位置消息
        else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)){
            message = MessageFactory.createTextMessage(fromUserName, toUserName,"您发送的是地理位置消息!");
        }
        // 链接消息
        else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) {
            message = MessageFactory.createTextMessage(fromUserName, toUserName,"您发送的是链接消息!");
        }
        // 音频消息
        else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) {
            message = MessageFactory.createTextMessage(fromUserName, toUserName,"您发送的是音频消息!");
        }
        // 事件推送
        else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {
            // 事件类型
            String eventType = requestMap.get("Event");
            // 订阅
            if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) {
                message = MessageFactory.createTextMessage(fromUserName, toUserName,ContentUtil.getMainTips());
            }
            // 取消订阅
            else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) {
            // TODO 取消订阅后用户再收不到公众号发送的消息,因此不需要回复消息
            }
            // 自定义菜单点击事件
            else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) {
            // TODO 自定义菜单权没有开放,暂不处理该类消息
            }
        }
        return message;
    }


}

你可能感兴趣的:(微信公众号开发(二):利用责任链和模板方法模式设计消息的处理流程)