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

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 条评论
登录 后参与评论

相关文章

来自专栏.Net Core 开发记录

[译]ASP.NET Core依赖注入深入讨论

这篇文章我们来深入探讨ASP.NET Core、MVC Core中的依赖注入,我们将示范几乎所有可能的操作把依赖项注入到组件中。

731
来自专栏专注 Java 基础分享

Struts2框架的基本使用

     前面已经介绍过了MVC思想,Struts2是一个优秀的MVC框架,大大降低了各个层之间的耦合度,具有很好的扩展性。从本篇开始我们学习Struts2的基...

1947
来自专栏陈树义

【Struts】Struts框架配置详解

1.首先将所必须的Jar包放到项目的WebRoot/WEB-INF/lib目录下。 如果你没有这些Jar文件,你可以到Struts官网上下载:http://st...

3397
来自专栏JavaEE

mybatis-plus的使用 ------ 进阶

关于mybatis-plus的简介以及基本使用,我在《mybatis-plus的使用 ------ 入门》一文中已做介绍,此处不再赘述。本文主要对mybatis...

1885
来自专栏大内老A

ASP.NET MVC集成EntLib实现“自动化”异常处理[实例篇]

个人觉得异常处理对于程序员来说是最为熟悉的同时也是最难掌握的。说它熟悉,因为仅仅就是try/catch/finally而已。说它难以掌握,则是因为很多开发人员却...

18410
来自专栏java技术学习之道

SpringBoot开发详解 --Controller接收参数以及参数校验

1144
来自专栏算法修养

javaWeb项目(SSH框架+AJAX+百度地图API+Oracle数据库+MyEclipse+Tomcat)之二 基础Hibernate框架搭建篇

   我们在搭建完Struts框架之后,从前台想后端传送数据就显得非常简单了。Struts的功能不仅仅是一个拦截器,这只是它的核心功能,此外我们也可以自定义拦截...

3219
来自专栏逸鹏说道

避免在ASP.NET Core中使用服务定位器模式

题记:服务定位器(Service Locator)作为一种反模式,一般情况下应该避免使用,在ASP.NET Core更是需要如此。 Scott Allen在其博...

2758
来自专栏抠抠空间

Django之views系统

Django的View(视图)简介 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应。 响应可以是一张网页...

3497
来自专栏陈树义

注解的那些事儿(一)| 为什么要使用注解?

注解是 JDK 1.5 引入的功能,相信不少开发者都使用过这个功能,但关于为什么要使用注解,你了解过多少呢?

784

扫码关注云+社区