反射在微信公众平台开发中的应用

1、开发背景

在微信公众号开发的时候,我们都会去解析微信消息,然后根据不同的消息类型做对应的操作。下面是一段微信的消息体:

<xml>

 <ToUserName><![CDATA[toUser]]></ToUserName>

 <FromUserName><![CDATA[fromUser]]></FromUserName>

 <CreateTime>1348831860</CreateTime>

 <MsgType><![CDATA[MsgType]]></MsgType>

 <MsgId>1234567890123456</MsgId>

</xml>

这里的MsgType有8种,分别是text、event。这么多中消息类型,怎么办呢?if...else,switch?都可以处理,看起来It's too simple。

那么问题来了,还有事件消息event。这个消息有关注,取关,上传地理位置以及自定义菜单等。看消息体:

<xml>

    <ToUserName><![CDATA[toUser]]></ToUserName>

    <FromUserName><![CDATA[FromUser]]></FromUserName>

    <CreateTime>123456789</CreateTime>

    <MsgType><![CDATA[event]]></MsgType>

    <Event><![CDATA[subscribe]]></Event>

</xml>

事件消息都是event类型,具体的事件(点击了不同的按钮)对应一个Event,在自定义菜单的时候,那这个Event就有N种了。如果都用分支结构去写,那就有点尴尬了。所以呢,为了解决这种尴尬,下面引入一个概念——反射。

2、反射

反射是什么呢?说起这个概念,笔者表示一脸懵逼。我不记得,下面请看一几个例子。

2.1通过一个对象获得完整的包名和类名

public static void main(String[] args) {
    Demo demo=new Demo();
    System.out.println(demo.getClass().getName());
}

2.2实例化Class类对象

Class<?> demo1=null;

demo1=Class.forName("com.example.bean.Demo");

注意: 还有很多示例,请移驾到baidu.com

在你百度了一下你就会发现,我的两个简单的例子也是copy过来的。不过还是要总结一下反射有什么用:

在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

看完了上面这一段解释,是不是一脸懵逼,没关系,接着看,从例子中理解反射的作用。

3、反射在微信公众平台开发中的应用

/**
 * 微信事件     
**/
public interface WechatEventCenter {

      /**
     * @功能描述: 微信默认回复
     */
    public BaseWechatMsg defaultEvent();

    /**
     * @功能描述: 文本消息
     */
    public BaseWechatMsg text();

    /**
     * @功能描述: 位置消息
     */
    public BaseWechatMsg location();

    /**
     * @功能描述: 语音消息
     */
    public BaseWechatMsg voice();

    /**
     * @功能描述: <p>事件消息</p>
     */
    public BaseWechatMsg event();

    /**
     * @功能描述: <p>用户未关注时,进行关注后的事件推送</p>
     * @return
     */
    public BaseWechatMsg subscribe();

    /**
     * @功能描述: 按钮1, 创建按钮时对应的EventKey为方法名
     * 所以这里的方法名看着有点怪啊,没有按java的命名规范来,
     * 你也可以按照自己的喜好来定义
     */
    public BaseWechatMsg EVENT_HOME();

}
/**
 * 微信接入入口
 **/
@RequestMapping(value="index")
@ResponseBody
public String wechat(HttpServletRequest request, HttpServletResponse response, 
    String signature, String timestamp, String nonce, String echostr) {
    String result = "";
    String method = request.getMethod();
    if("GET".equals(method)){//接入验证
        return echostr;//直接返回echostr便接入成功了,此处省略了解密验证
    } else {//消息处理
        result = dopost(request);
    }
    return result;
}

接入成功了之后了,下面就到了重点了,直接上代码:

private String dopost(HttpServletRequest request){

    BaseWechatMsg wechatMsg;
   try {
        String sReqData = WechatUtils.convertStreamToString(request.getInputStream());
      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
      DocumentBuilder db = dbf.newDocumentBuilder();
      StringReader sr = new StringReader(sReqData);
      InputSource is = new InputSource(sr);
      Document document = db.parse(is);
      Element root = document.getDocumentElement();
      String FromUserName = root.getElementsByTagName(HqWechatConstant.FromUserName).item(0).getTextContent();
      System.out.println("用户: "+FromUserName+" 进入wechat. ");
      System.out.println("用户消息为:\r\n" + sReqData);
      String msgType = root.getElementsByTagName(HqWechatConstant.MsgType).item(0).getTextContent();
      wechatEventCenter.setRoot(root);//参数注入
         //根据事件类型获取要执行的方法
      Method method = wechatEventCenter.getClass().getMethod(msgType);
         //用反射根据方法名调用方法
      wechatMsg = (BaseWechatMsg) method.invoke(wechatEventCenter);
   } catch (Exception e) {
          //调用默认方法
        wechatMsg = (BaseWechatMsg) wechatEventCenter.defaultEvent();
        e.printStackTrace();
   } finally {
    }
    System.out.println("回复消息为:\r\n"+wechatMsg);
   return wechatMsg.toString();

}

这里的处理就用到了反射了,就是下面这两行代码:

Method method = wechatEventCenter.getClass().getMethod(msgType);

wechatMsg = (BaseWechatMsg) method.invoke(wechatEventCenter);

这样整个过程就完成了,在处理事件消息的时候也是一样的根据事件的EventKey去调用对应的方法就OK了,这里就不赘述了。

4、总结

在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

仅供参考,不足之处还请见谅,欢迎指正!

原文发布于微信公众号 - java工会(javagonghui)

原文发表时间:2018-05-24

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Google Dart

Dart 服务端开发 shelf_bind 包

shelf_bind倾向于约定优于配置,因此您可以编写必要的最小代码,但仍然可以根据需要覆盖默认值。

852
来自专栏noteless

ServletRequest HttpServletRequest 请求方法 获取请求参数 请求转发 请求包含 请求转发与重定向区别 获取请求头字段

实际为   HttpServletRequest  或者  ServletRequest,   两者都为接口

1485
来自专栏云瓣

Node.js 异步异闻录

提到 Node.js, 我们脑海就会浮现异步、非阻塞、单线程等关键词,进一步我们还会想到 buffer、模块机制、事件循环、进程、V8、libuv 等知识点。本...

3678
来自专栏嵌入式程序猿

freeRTOS任务创建

我们曾经在公众号里给大家推送过关于freeRTOS在NXP kinetis KV4x上的移植,得到了猿友大量的反馈,很多猿友还是感觉对基础的一些东西不懂,今天我...

3947
来自专栏desperate633

深入理解Java多线程(multiThread)多线程的基本概念线程同步wait,notify,notifyAll线程的生命周期

一个java程序启动后,默认只有一个主线程(Main Thread)。如果我们要使用主线程同时执行某一件事,那么该怎么操作呢? 例如,在一个窗口中,同时画两排...

1262
来自专栏封碎

Java多线程参考手册 博客分类: 经典文章转载

http://blog.csdn.net/ring0hx/article/details/6858582

652
来自专栏佳爷的后花媛

路由&模块化设计&命名空间

ThinkPHP采用模块化的架构思想,可以支持多模块应用的创建,让应用的扩展更加方便. 先简单说下路由规则:

1543
来自专栏武培轩的专栏

京东面经汇总

一、Java Java的优势 平台无关性、垃圾回收 Java有哪些特性,举个多态的例子。 封装、继承、多态 abstract interface区别 含有abs...

5236
来自专栏前端杂货铺

AngularJS源码分析之依赖注入$injector

开篇 随着javaEE的spring框架的兴起,依赖注入(IoC)的概念彻底深入人心,它彻底改变了我们的编码模式和思维。在IoC之前,我们在程序中需要创建一个...

3255
来自专栏游戏杂谈

Node.js文件编码格式的转换

项目很多 lua 文件不是 utf-8格式,使用 EditPlus 查看的时候,显示为ASCII。还有的是带BOM的,带BOM倒好处理,之前写过,有一定规律。

1404

扫码关注云+社区