微信开发处理点击事件_微信小程序云开发,在群消息中点击微信小程序获取微信群信息 - CSDN
  • 本博将从项目的建立开始 首先建立一个web项目 然后导入相应的包(不一定是全的,看具体的项目要求)

    来自微信端的事件可以有多种

    1:文本消息

    2:图片消息

    3:语音消息

    4:点击按钮事件

    5:扫码事件等等

    用户发送的消息或者事件  都是以xml的形式发送给我们开发者的(也就是服务器端) 我们也是以xml的格式返回去的

    这是开发者文档点击打开链接


    所有首先 我们得把用户的消息给获取并解析了(我给出一个工具类类  )

    可以看出就是把传过来的request直接传进去就ok了

     public static Map<String,String> xmlToMap(HttpServletRequest request) throws IOException, DocumentException{
    	  //用List列表的方式来解析xml,详细见http://www.jb51.net/article/42323.htm
    	  Map<String, String> map =new HashMap<String,String>();  //把客户端传过来的xml数据转换成map格式的数据
    	  
    	  SAXReader reader =new SAXReader();
    	  
    	  
    	  InputStream ins=request.getInputStream();//从request中获取输入流
    	  Document doc =reader.read(ins);// 弄成文本???Xml
    		
    	  Element root =doc.getRootElement();
    	  List<Element> list =root.elements();//获取子节点元素
    		//list相当于一个变量,List则是标明是何种变量,这样来理解
    		for(Element e :list){
    		   map.put(e.getName(), e.getText());	                 //将遍历的结果保存到集合中
    		}
    	    ins.close();
    	    return map;
    	  
      }
    然后当然就是获取map里面的数据了

    所以我们得根据他们的类型(是文字 还在图片 还是点击 ,,)

    Map<String ,String> map =BaseMessageUtil.xmlToMap(req);  //把服务器传过来的xml格式的数据转换成map
    			String fromUserName =map.get("FromUserName");//发送方帐号(一个OpenID)
    			String toUserName =map.get("ToUserName");//开发者微信号
    			String msgType =map.get("MsgType");//text
    			String content =map.get("Content");//文本消息内容
    请注意 图片的msgtype是image

                 文字的msgtype是text

                 语音的msgtype是voice

                 .....................

    但是事件的msgtype都是event (包括点击事件click 关注事件 扫码事件) 区分他们的唯一标示是 他们的map里面有一个event字段 可以将他们区分

    获取 String eventType = map.get("Event");   //事件的类型



    好了事件获取完毕就开始一一回击吧

    刚刚说过 回复也要包装成xml返回的

    所以制作完回复消息后就要转换成xml了再输出到微信端【out.print(message);】

    消息的制作就以图文消息为例

    首先新建一个基本消息父类

    package com.po;
    
    public class BaseMessage {
    	private String ToUserName;//微信号
    	 private String FromUserName;//用户的openID
    	 private long CreateTime;//创建时间
    	 private String MsgType;//消息类型
    	public String getToUserName() {
    		return ToUserName;
    	}
    	public void setToUserName(String toUserName) {
    		ToUserName = toUserName;
    	}
    	public String getFromUserName() {
    		return FromUserName;
    	}
    	public void setFromUserName(String fromUserName) {
    		FromUserName = fromUserName;
    	}
    	public long getCreateTime() {
    		return CreateTime;
    	}
    	public void setCreateTime(long createTime) {
    		CreateTime = createTime;
    	}
    	public String getMsgType() {
    		return MsgType;
    	}
    	public void setMsgType(String msgType) {
    		MsgType = msgType;
    	}
    }
    
    图文消息类


    一个总图文(PicNews)消息里面可以包含多个图文消息(PicNewsMessage)

    package com.po;
    
    public class PicNews {
      private String Title;
      private String Description;
      private String PicUrl;
      private String Url;
    public String getTitle() {
    	return Title;
    }
    public void setTitle(String title) {
    	Title = title;
    }
    public String getDescription() {
    	return Description;
    }
    public void setDescription(String description) {
    	Description = description;
    }
    public String getPicUrl() {
    	return PicUrl;
    }
    public void setPicUrl(String picUrl) {
    	PicUrl = picUrl;
    }
    public String getUrl() {
    	return Url;
    }
    public void setUrl(String url) {
    	Url = url;
    }
    }
    
    
    
    
    
    package com.po;
    
    import java.util.List;
    
    public class PicNewsMessage extends BaseMessage{    //图文消息的基本设置
        private int ArticleCount;
        private List<PicNews> Articles;//该集合中存放的是PicNews对象,每个对象都代表着一条图文消息
    	public int getArticleCount() {
    		return ArticleCount;
    	}
    	public void setArticleCount(int articleCount) {
    		ArticleCount = articleCount;
    	}
    	public List<PicNews> getArticles() {
    		return Articles;
    	}
    	public void setArticles(List<PicNews> articles) {
    		Articles = articles;
    	}
    }
    返回的时候只要填写数据就ok了
    填写好了之后就要把PicNewsMessage 对象转化成xml了
    话不多说  转化的代码(这是图文消息的转化)
    <pre name="code" class="java">
     public static String PicNewsMessageToXml(PicNewsMessage picNewsMessage){
     //返回一个Xml
     XStream xstream = new XStream();
     xstream.alias("xml", picNewsMessage.getClass());
     xstream.alias("item", new PicNews().getClass());//<articles>下根为<items>
     return xstream.toXML(picNewsMessage);
    }
    
    
    
    把转化完的消息放在message中out一下就到微信端了
    
    
    再把微信servlet代码贴上去
    <pre name="code" class="java">package com.servlet;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.sql.SQLException;
    import java.util.Date;
    import java.util.Map;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.dom4j.DocumentException;
    
    import com.po.TextMessage;
    import com.util.CheckUtil;
    import com.util.BaseMessageUtil;
    import com.util.ImageMessageUtil;
    import com.util.MusicMessageUtil;
    import com.util.PicNewsMessageUtil;
    import com.util.TextMessageUtil;
    import com.util.WeixinUtil;
    import com.xt.util.UserUtil;
    
    public class WeixinServlet extends HttpServlet {
        
    	
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    	@Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        		throws ServletException, IOException {  //验证方式为get
        	String signature = req.getParameter("signature");
        	String timestamp = req.getParameter("timestamp");
        	String nonce = req.getParameter("nonce");
        	String echostr = req.getParameter("echostr");
        	
        	PrintWriter out = resp.getWriter();
        	if(CheckUtil.checkSignature(signature, timestamp, nonce)){
        		out.print(echostr);
        	}
        	
        }
         protected void doPost(HttpServletRequest req ,HttpServletResponse resp) throws IOException {
        	 
        	 req.setCharacterEncoding("UTF-8");
        	 resp.setCharacterEncoding("UTF-8");
        	 
        	 /**
        	  * out是输出字符流,即servlet接受到request请求后,
        	  * servlet使用out来返回结果,不管客户端是什么(浏览器或者httpclient 或者别的serlvet等等),
        	  * 它都和客户端建立一个流输出管道,然后把字符流输出给请求端。
              */
        	 PrintWriter out =resp.getWriter(); 
    		 
    		    
        	 try {
    			Map<String ,String> map =BaseMessageUtil.xmlToMap(req);  //把服务器传过来的xml格式的数据转换成map
    			String fromUserName =map.get("FromUserName");//发送方帐号(一个OpenID)
    			String toUserName =map.get("ToUserName");//开发者微信号
    			String msgType =map.get("MsgType");//text
    			String content =map.get("Content");//文本消息内容
    			//String 
    			
    			//判断该消息是否为文本消息
    			String message =null;
    			if(BaseMessageUtil.MESSAGE_TEXT.equals(msgType)){  //发过来的时文本消息时
    				if("1".equals(content)){  //回复文本消息
    					System.out.println(this+"用户输入的是1");
    //					message = TextMessageUtil.initText(toUserName, fromUserName, TextMessageUtil.firstMenu(fromUserName)); 
    					message = PicNewsMessageUtil.initPicNewsMessage(toUserName, fromUserName,12);
    				}else if("2".equals(content)){  //回复图文消息
    					//message = PicNewsMessageUtil.initPicNewsMessage(toUserName, fromUserName);
    					 
    				}else if("3".equals(content)){  //回复图片消息
    					message = ImageMessageUtil.initImageMessage(toUserName, fromUserName);
    				}else if("4".equals(content)){  //回复音乐消息
    					message = MusicMessageUtil.initMusicMessage(toUserName, fromUserName);
    				}
    				else if("5".equals(content)){  //回复文本消息
    					message = TextMessageUtil.initText(toUserName, fromUserName,TextMessageUtil.threeMenu());
    				}
    				else if("?".equals(content)||"?".equals(content)){ //菜单
    					message = TextMessageUtil.initText(toUserName, fromUserName, TextMessageUtil.menuText(fromUserName));
    				}else if(content.startsWith("翻译")){
    					String word = content.replaceAll("^翻译", "").trim();
    					if("".equals(word)){
    						message = TextMessageUtil.initText(toUserName, fromUserName,TextMessageUtil.threeMenu());
    					}else{
    						//message = TextMessageUtil.initText(toUserName, fromUserName, WeixinUtil.translate(word));//翻译
    					}
    				}
    				
    			/**	   
    				   text.setFromUserName(toUserName);
    				   text.setToUserName(fromUserName);
    				   text.setMsgType("text");
    				   text.setCreateTime(new Date().getTime());
    				   text.setContent("您发送的消息是:"+content);
    				   TextMessage text =new TextMessage();
    				   message = TextMessageUtil.textMessageToXml(text);
    				 
    				*/
    				
    			}else if(BaseMessageUtil.MESSAGE_EVENT.equals(msgType)){  //当发过来的是事件
    				
    				String eventType = map.get("Event");   //点击事件的类型
    				if(BaseMessageUtil.MESSAGE_SUBSCRIBE.equals(eventType)){  //调出主菜单
    					message = TextMessageUtil.initText(toUserName, fromUserName, TextMessageUtil.menuText(fromUserName));
    					UserUtil userUtil=new UserUtil();
    					try {
    						userUtil.saveUser(fromUserName);//关注的时候往数据库里面插入用户的信息
    					} catch (ClassNotFoundException | SQLException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    				}else if(BaseMessageUtil.MESSAGE_CLICK.equals(eventType)){  //点击事件时,推送图文消息
    					int Key = Integer.parseInt(map.get("EventKey"));  //得到按钮的key值
    					message = PicNewsMessageUtil.initPicNewsMessage(toUserName, fromUserName,Key);
    					
    				}else if(BaseMessageUtil.MESSAGE_VIEW.equals(eventType)){  //链接事件
    					System.out.println("你点击了ViewButton");
    					message = TextMessageUtil.initText(toUserName, fromUserName, TextMessageUtil.menuText(fromUserName));
    //					String url = map.get("EventKey"); 
    //					message = TextMessageUtil.initText(toUserName, fromUserName, url);
    				}else if(BaseMessageUtil.MESSAGE_SCANCODE.equals(eventType)){  //扫码事件,推送消息
    					
    					String key =map.get("EventKey");
    					System.out.println(key);
    					//message = TextMessageUtil.initText(toUserName, fromUserName, key);
    
    				}else if(BaseMessageUtil.MESSAGE_LOCATION.equals(eventType)){
    					String label = map.get("Label");
    					message = TextMessageUtil.initText(toUserName, fromUserName, label);
    				}
    				else if(BaseMessageUtil.MESSAGE_SCAN.equals(eventType)){
    					String scene_id = map.get("EventKey");
    					System.out.println(scene_id);
    					
    				}
    				
    				
    				
    				
                }
    			
    			//System.out.println(message);
    			
    			out.print(message);
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (DocumentException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
        	 finally{
        		 out.close();
        		 
        	 }
    	}
    }
    


    
    

    展开全文
  • 1.0 开发背景 外包公司,所以各种各样的项目都有接触,有个需求,客户要做不同的二维码,通过二维码关注以后,给用户发送不同的消息,顺便统计用户来源, 本文用到了 微信带参数二维码接口和消息管理里的相关...

    1.0 开发背景
    外包公司,所以各种各样的项目都有接触,有个需求,客户要做不同的二维码,通过二维码关注以后,给用户发送不同的消息,顺便统计用户来源,
    本文用到了 微信带参数二维码接口和消息管理里的相关接口
    注意 :在微信公众号后台,设置了服务器配置 URL 并启用后,会导致 微信后台设置的回复规则,以及底部菜单都全部失效!直接清空了!因为这时候 微信已经把公众号消息和事件 推送给开发者配置的url中,让开发者进行处理了。
    本文先讲述微信官方后台设置带参二维码,后续更新使用第三方平台开发实现这个功能,从而保证了用户微信公众号官方设置底部菜单以及自定义回复没有失效!

    2.0 开发准备
    2.1老样子 官方文档 来一波 带参二维码 接收事件
    2.2 需要在微信后台 配置服务器配置 ,微信会在你修改这个配置的时候 给你填写的URL发送数据,需要提前把项目上传服务器!
    这里写图片描述

    这个东西 配置好之后 可以点击开启了 ,开启后啊,这个微信会把所有用户发送的信息,给转发给填写的url 上。开发者必须在五秒内回复微信服务器。否则 微信会进行三次重试,重试均失败后,会给用户提示 该公众号暂时无法提供服务。 而且在公众平台还有告警通知。

    下面看代码

    package com.ysh.wxtest.controller;
    
    import org.apache.log4j.Logger;
    import org.dom4j.Document;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import weixin.popular.bean.xmlmessage.XMLMessage;
    import weixin.popular.bean.xmlmessage.XMLTextMessage;
    import weixin.popular.support.ExpireKey;
    import weixin.popular.support.expirekey.DefaultExpireKey;
    import weixin.popular.util.SignatureUtil;
    
    import javax.servlet.ServletInputStream;
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.*;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 消息接收控制层
     * @author YaoShiHang
     * @Date 15:15 2017-10-16
     */
    @Controller
    public class WxqrcodeController {
    
        private final String TOKEN="xxxxxxxxxx";                      //Wx 开发者设置的 token
        private Logger loger = Logger.getLogger(getClass());
        //重复通知过滤
        private static ExpireKey expireKey = new DefaultExpireKey();
    
    
        //微信推送事件 url
        @RequestMapping("/openwx/getticket")
        public void getTicket(HttpServletRequest request, HttpServletResponse response)
                throws Exception {
            ServletInputStream inputStream = request.getInputStream();
            ServletOutputStream outputStream = response.getOutputStream(); String signature = request.getParameter("signature");
            String timestamp = request.getParameter("timestamp");
            String nonce = request.getParameter("nonce");
            String echostr = request.getParameter("echostr");
    
            //首次请求申请验证,返回echostr
            if(echostr!=null){
                outputStreamWrite(outputStream,echostr);
                return;
            }
    
            //验证请求签名
            if(!signature.equals(SignatureUtil.generateEventMessageSignature(TOKEN,timestamp,nonce))){
                System.out.println("The request signature is invalid");
                return;
            }
    
            boolean isreturn= false;
            loger.info("1.收到微信服务器消息");
            Map<String, String> wxdata=parseXml(request);
            if(wxdata.get("MsgType")!=null){
                if("event".equals(wxdata.get("MsgType"))){
                    loger.info("2.1解析消息内容为:事件推送");
                    if( "subscribe".equals(wxdata.get("Event"))){
                        loger.info("2.2用户第一次关注 返回true哦");
                        isreturn=true;
                    }
                }
            }
    
            if(isreturn == true){
                //转换XML
                String key = wxdata.get("FromUserName")+ "__"
                        + wxdata.get("ToUserName")+ "__"
                        + wxdata.get("MsgId") + "__"
                        + wxdata.get("CreateTime");
                loger.info("3.0 进入回复 转换对象:"+key);
    
                if(expireKey.exists(key)){
                    //重复通知不作处理
                    loger.info("3.1  重复通知了");
                    return;
                }else{
                    loger.info("3.1  第一次通知");
                    expireKey.add(key);
                }
    
                loger.info("3.2  回复你好");
                //创建回复
                XMLMessage xmlTextMessage = new XMLTextMessage(
                        wxdata.get("FromUserName"),
                        wxdata.get("ToUserName"),
                        "你好");
                //回复
                xmlTextMessage.outputStreamWrite(outputStream);
                return;
            }
            loger.info("3.2  回复空");
            outputStreamWrite(outputStream,"");
        }
    
        /**
         * 数据流输出
         * @param outputStream
         * @param text
         * @return
         */
        private boolean outputStreamWrite(OutputStream outputStream, String text){
            try {
                outputStream.write(text.getBytes("utf-8"));
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return false;
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return false;
            }
            return true;
        }
    
        /**
         * dom4j 解析 xml 转换为 map
         * @param request
         * @return
         * @throws Exception
         */
        public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
            // 将解析结果存储在HashMap中
            Map<String, String> map = new HashMap<String, String>();
            // 从request中取得输入流
            InputStream inputStream = request.getInputStream();
            // 读取输入流
            SAXReader reader = new SAXReader();
            Document document = reader.read(inputStream);
            // 得到xml根元素
            Element root = document.getRootElement();
            // 得到根元素的所有子节点
            List<Element> elementList = root.elements();
    
            // 遍历所有子节点
            for (Element e : elementList)
                map.put(e.getName(), e.getText());
    
            // 释放资源
            inputStream.close();
            inputStream = null;
            return map;
        }
    
        /**
         * 回复微信服务器"文本消息"
         * @param response
         * @param returnvaleue
         */
        public void output(HttpServletResponse response, String returnvaleue) {
            try {
                PrintWriter pw = response.getWriter();
                pw.write(returnvaleue);
                loger.info("****************return valeue***************="+returnvaleue);
                pw.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    提供一个大神的帮助类

    package weixin.popular.bean.xmlmessage;
    
    import java.io.IOException;
    import java.io.OutputStream;
    import java.io.UnsupportedEncodingException;
    import java.util.UUID;
    
    import com.qq.weixin.mp.aes.AesException;
    import com.qq.weixin.mp.aes.WXBizMsgCrypt;
    
    import weixin.popular.bean.message.message.Message;
    
    public abstract class XMLMessage {
    
        protected String toUserName;
        protected String fromUserName;
        protected String msgType;
    
        protected XMLMessage(String toUserName, String fromUserName, String msgType) {
            super();
            this.toUserName = toUserName;
            this.fromUserName = fromUserName;
            this.msgType = msgType;
        }
    
        /**
         * 子类自定义XML
         * @return XML
         */
        public abstract String subXML();
    
        /**
         * 转换为  Message 对象
         * @return Message
         */
        public abstract Message convert();
    
        public String toXML(){
            StringBuilder sb = new StringBuilder();
            sb.append("<xml>");
            sb.append("<ToUserName><![CDATA["+toUserName+"]]></ToUserName>");
            sb.append("<FromUserName><![CDATA["+fromUserName+"]]></FromUserName>");
            sb.append("<CreateTime>"+System.currentTimeMillis()/1000+"</CreateTime>");
            sb.append("<MsgType><![CDATA["+msgType+"]]></MsgType>");
            sb.append(subXML());
            sb.append("</xml>");
            return sb.toString();
        }
    
        public boolean outputStreamWrite(OutputStream outputStream){
            try {
                outputStream.write(toXML().getBytes("utf-8"));
                outputStream.flush();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                return false;
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            }
            return true;
        }
    
        public boolean outputStreamWrite(OutputStream outputStream,WXBizMsgCrypt bizMsgCrypt){
            if(bizMsgCrypt != null){
                try {
                    String outputStr = bizMsgCrypt.encryptMsg(toXML(), System.currentTimeMillis()+"",UUID.randomUUID().toString());
                    outputStream.write(outputStr.getBytes("utf-8"));
                    outputStream.flush();
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                    return false;
                } catch (IOException e) {
                    e.printStackTrace();
                    return false;
                } catch (AesException e) {
                    e.printStackTrace();
                    return false;
                }
                return true;
            }else{
                return outputStreamWrite(outputStream);
            }
        }
    
        public String getToUserName() {
            return toUserName;
        }
    
        public String getFromUserName() {
            return fromUserName;
        }
    
        public String getMsgType() {
            return msgType;
        }
    
    
    }
    
    展开全文
  • 当普通微信用户向公众号发送消息或者与微信公众号进行互动触发某些事件时,微信服务器将会把这些消息或者事件以XML数据包格式POST到开发者配置的服务器地址URL上
    
    
    在成功接入微信公众平台之后(如何接入请参考《微信公众号开发:账号申请与接入》),就可以对微信服务器POST过来的消息或者事件XML数据包进行监听与处理了。

    《微信公众号开发:账号申请与接入》的 WeChatController 控制器中, handleMsgAndEvent() 方法用来监听并处理消息与事件,示例项目的完整目录层次如下图所示。

    本示例使用了Maven来构建工程,除了要引入基本的SpringMVC-WEB依赖,还需引入以下三个工具包。
    		<dependency>
    			<groupId>dom4j</groupId>
    			<artifactId>dom4j</artifactId>
    		</dependency>
    		<dependency>
    			<groupId>xstream</groupId>
    			<artifactId>xstream</artifactId>
    			<version>1.2.2</version>
    		</dependency>
    		<dependency>
    			<groupId>org.projectlombok</groupId>
    			<artifactId>lombok</artifactId>
    		</dependency>
    WeChatController 控制器和 WeChatEncrypt  加密工具类的完整代码在《微信公众号开发:账号申请与接入》中已经贴出,此章中不再重复贴出。
    WechatSession 是处理所有消息的入口。
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.PrintWriter;
    
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.parsers.ParserConfigurationException;
    import javax.xml.transform.TransformerFactory;
    
    import org.w3c.dom.Document;
    import org.xml.sax.SAXException;
    
    /**
     * 处理消息和事件的入口类
     */
    public class WechatSession
    
    {
    
        private InputStream in;
    
        private PrintWriter out;
    
        public static TransformerFactory tffactory = TransformerFactory.newInstance();
    
        private static DocumentBuilder documentBuilder = null;
    
        public static DocumentBuilder getDocumentBuilder()
        {
            // 先检查实例是否已创建,如果未创建才进入同步块
            if (null == documentBuilder)
            {
                synchronized (WechatSession.class)
                {
                    // 再次检查实例是否已创建,如果真的未创建才创建实例
                    if (null == documentBuilder)
                    {
                        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                        try
                        {
                            documentBuilder = factory.newDocumentBuilder();
                        }
                        catch (ParserConfigurationException e)
                        {
                            e.printStackTrace();
                        }
                    }
                }
            }
            return documentBuilder;
        }
    
        /**
         * 构造方法
         * 
         * @param in
         * @param out
         */
        public WechatSession(InputStream in, PrintWriter out)
        {
            this.in = in;
            this.out = out;
        }
    
        /**
         * 对接收到的消息和事件进行处理
         */
        public void process()
    
        {
            try
            {
                Document document = getDocumentBuilder().parse(in);
                String msgType = document.getElementsByTagName("MsgType").item(0).getTextContent();
    
                if ("text".equals(msgType))
                {
                    TextMsg msg = new TextMsg();
                    msg.read(document);
                    msg.onTextMsg(out);
                }
                else if ("event".equals(msgType))
                {
                    EventMsg msg = new EventMsg();
                    msg.read(document);
                    msg.onEventMsg(out);
                }
            }
            catch (SAXException e)
            {
                e.printStackTrace();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    
        public void close()
    
        {
            try
            {
                if (in != null)
                {
                    in.close();
                }
                if (out != null)
                {
                    out.flush();
                    out.close();
                }
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    
    }
    
    AbstractMsg 是普通消息与事件消息公用的抽象父类,包含了一些通用的基础属性、提供了一些通用的基础方法。
    import java.io.IOException;
    import java.io.StringWriter;
    
    import javax.xml.transform.OutputKeys;
    import javax.xml.transform.Transformer;
    import javax.xml.transform.dom.DOMSource;
    import javax.xml.transform.stream.StreamResult;
    
    import org.w3c.dom.CDATASection;
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    
    import lombok.Data;
    
    /**
     * 消息与事件的抽象父类
     */
    @Data
    public abstract class AbstractMsg
    {
        protected String toUserName;
        protected String fromUserName;
        protected String createTime;
        protected String msgType;
    
        /**
         * 读取Document内容到Java对象
         * 
         * @param document
         */
        public void read(Document document)
        {
            readHead(document);
            readBody(document);
        }
    
        /**
         * 获取Java对象的XML字符串
         */
        public String write()
        {
            Document document = WechatSession.getDocumentBuilder().newDocument();
            Element root = document.createElement("xml");
            writeHead(root, document);
            writeBody(root, document);
            document.appendChild(root);
            return readDocument(document);
        }
    
        /**
         * 读取消息和事件公有的一些基础属性
         * 
         * @param document
         */
        private void readHead(Document document)
        {
            toUserName = document.getElementsByTagName("ToUserName").item(0).getTextContent();
            fromUserName = document.getElementsByTagName("FromUserName").item(0).getTextContent();
            createTime = document.getElementsByTagName("CreateTime").item(0).getTextContent();
            msgType = document.getElementsByTagName("MsgType").item(0).getTextContent();
    
        }
    
        /**
         * 消息和事件具体子类需实现该方法,用来读取一些自身独有的属性数据
         * 
         * @param document
         */
        protected abstract void readBody(Document document);
    
        /**
         * 将Java对象中的基础属性写入Document
         * 
         * @param root
         * @param document
         */
        private void writeHead(Element root, Document document)
        {
            Element toUserNameElement = document.createElement("ToUserName");
            CDATASection toUserNameCData = document.createCDATASection(this.toUserName);
            toUserNameElement.appendChild(toUserNameCData);
            Element fromUserNameElement = document.createElement("FromUserName");
            CDATASection fromUserNameCData = document.createCDATASection(this.fromUserName);
            fromUserNameElement.appendChild(fromUserNameCData);
            Element createTimeElement = document.createElement("CreateTime");
            createTimeElement.setTextContent(this.createTime);
            Element msgTypeElement = document.createElement("MsgType");
            CDATASection msgTypeCData = document.createCDATASection(this.msgType);
            msgTypeElement.appendChild(msgTypeCData);
    
            root.appendChild(toUserNameElement);
            root.appendChild(fromUserNameElement);
            root.appendChild(createTimeElement);
            root.appendChild(msgTypeElement);
        }
    
        /**
         * 消息和事件各子类需实现该方法,用来写入一些自身独有的属性数据
         * 
         * @param root
         * @param document
         */
        protected abstract void writeBody(Element root, Document document);
    
        /**
         * 获取Document对象中指定元素的内容
         * 
         * @param document
         * @param elementName
         * @return
         */
        protected String getElementContent(Document document, String elementName)
        {
            if (document.getElementsByTagName(elementName).getLength() > 0)
            {
                return document.getElementsByTagName(elementName).item(0).getTextContent();
            }
            return null;
        }
    
        /**
         * 读取Document对象为XML字符串
         * 
         * @param document
         */
        private String readDocument(Document document)
        {
            String docXml = "";
            StringWriter writer = new StringWriter();
            try
            {
                Transformer transformer = WechatSession.tffactory.newTransformer();
                transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");// 设置编码字符集
                transformer.setOutputProperty(OutputKeys.INDENT, "yes");// 设置缩进
    
                transformer.transform(new DOMSource(document), new StreamResult(writer));
                docXml = writer.getBuffer().toString();
                System.out.println(docXml);// 将获取到的XML字符串打印至控制台
                writer.close();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            finally
            {
                if (null != writer)
                {
                    try
                    {
                        writer.close();
                    }
                    catch (IOException e)
                    {
                        e.printStackTrace();
                    }
                }
            }
            return docXml;
    
        }
    
    }
    
    TextMsg 普通消息Java类。
    import java.io.PrintWriter;
    
    import org.w3c.dom.CDATASection;
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    
    /**
     * 普通文本消息
     */
    @Data
    @EqualsAndHashCode(callSuper = false)
    public class TextMsg extends AbstractMsg
    {
        private String content;
        private String msgId;
    
        /**
         * 从Document中读取普通文本消息独有的属性数据
         */
        @Override
        protected void readBody(Document document)
        {
            content = document.getElementsByTagName("Content").item(0).getTextContent();
            msgId = document.getElementsByTagName("MsgId").item(0).getTextContent();
        }
    
        /**
         * 回复时专用,将普通文本消息独有的回复内容写入Document中
         */
        @Override
        protected void writeBody(Element root, Document document)
        {
            Element contentElement = document.createElement("Content");
            CDATASection contentCData = document.createCDATASection(this.content);
            contentElement.appendChild(contentCData);
            root.appendChild(contentElement);
        }
    
        public void onTextMsg(PrintWriter out)
        {
            System.out.println("此处添加处理普通文本消息的业务逻辑,此处简单回复:你好 某某某");
            TextMsg msg = new TextMsg();
            msg.setFromUserName(this.toUserName);
            msg.setToUserName(this.fromUserName);
            msg.setCreateTime(this.createTime);
            msg.setMsgType("text");
            msg.setContent("你好 " + this.fromUserName);
            out.print(msg.write());
        }
    
    }
    
    EventMsg 事件消息Java类。
    import java.io.PrintWriter;
    
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    
    /**
     * 事件统一处理类
     */
    @Data
    @EqualsAndHashCode(callSuper = false)
    public class EventMsg extends AbstractMsg {
    	// 事件列表:CLICK(点击自定义菜单)/subscribe(关注)/unsubscribe(取消关注)/SCAN(扫描二维码)/LOCATION(上报地理位置)
    	private String event;
    
    	private String eventKey;
    	private String ticket;
    
    	private String latitude;
    	private String longitude;
    	private String precision;
    
    	/**
    	 * 从Document中读取各事件独有的属性数据
    	 */
    	@Override
    	protected void readBody(Document document) {
    		event = getElementContent(document, "Event").toLowerCase();
    		switch (event) {
    		case "click": {
    			eventKey = getElementContent(document, "EventKey");
    			break;
    		}
    		case "subscribe":
    		case "unsubscribe":
    		case "scan": {
    			eventKey = getElementContent(document, "EventKey");
    			ticket = getElementContent(document, "Ticket");
    			break;
    		}
    		case "location": {
    			latitude = getElementContent(document, "Latitude");
    			longitude = getElementContent(document, "Longitude");
    			precision = getElementContent(document, "Precision");
    			break;
    		}
    		default: {
    			break;
    		}
    		}
    	}
    
    	/**
    	 * 回复时专用,由于事件无须回复,在此空实现
    	 */
    	@Override
    	protected void writeBody(Element root, Document document) {
    	}
    
    	public void onEventMsg(PrintWriter out) {
    		System.out
    				.println("此处添加处理事件的业务逻辑,对于关注事件回复:尊敬的 某某某 女士/先生,欢迎您关注我的个人公众号!");
    		switch (event) {
    			case "subscribe": {
    				TextMsg msg = new TextMsg();
    				msg.setFromUserName(this.toUserName);
    				msg.setToUserName(this.fromUserName);
    				msg.setCreateTime(this.createTime);
    				msg.setMsgType("text");
    				msg.setContent("尊敬的 " + this.fromUserName + " 女士/先生,欢迎您关注我的个人公众号!");
    				out.print(msg.write());
    				break;
    			}
    		}
    	}
    }
    
    本文项目源码已上传至CSDN,资源地址:http://download.csdn.net/download/pengjunlee/10257857
    展开全文
  • 本例中有些引用的类与方法不做过多介绍,之后会提供完整源码下载,请自行查看。本篇根据开发者文档-接收事件推送... ​在微信用户和公众号产生交互的过程中,用户的某些操作会使得微信服务器通过事件推送的形式通知到

    本例中有些引用的类与方法不做过多介绍,之后会提供完整源码下载,请自行查看。

    本篇根据开发者文档-接收事件推送编写。请对照查看,一些传入与返回参数就不过多介绍。地址为:https://mp.weixin.qq.com/wiki/14/f79bdec63116f376113937e173652ba2.html


    ​在微信用户和公众号产生交互的过程中,用户的某些操作会使得微信服务器通过事件推送的形式通知到开发者在开发者中心处设置的服务器地址,从而开发者可以获取到该信息。其中,某些事件推送在发生后,是允许开发者回复用户的,某些则不允许

    关注/取消关注事件

    用户在关注与取消关注公众号时,微信会把这个事件推送到开发者填写的URL。方便开发者给用户下发欢迎消息或者做帐号的解绑。

    微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次

    关于重试的消息排重,推荐使用FromUserName + CreateTime 排重。

    假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。

    /*
     * 接收事件推送消息
     * http://mp.weixin.qq.com/wiki/2/5baf56ce4947d35003b86a9805634b1e.html
     */
    @XmlRootElement
    public class MsgBaseEvent {
    
        @XmlElement(name = "ToUserName")  
        private String ToUserName;      //开发者微信号
    
        @XmlElement(name = "FromUserName")  
        private String FromUserName;    //发送方帐号(一个OpenID)
    
        @XmlElement(name = "CreateTime")  
        private long CreateTime;        //消息创建时间 (整型)
    
        @XmlElement(name = "MsgType")  
        private String MsgType;         //消息类型,event
    
        @XmlElement(name = "Event")  
        private String Event;           //事件类型
    }

    扫描带参数二维码事件

    用户扫描带场景值二维码时,可能推送以下两种事件:

    • 如果用户还未关注公众号,则用户可以关注公众号,关注后微信会将带场景值关注事件推送给开发者。
    • 如果用户已经关注公众号,则微信会将带场景值扫描事件推送给开发者。
      /*
       * 用户未关注时,进行关注后的事件推送
       * Event    事件类型,subscribe
       * EventKey 事件KEY值,qrscene_为前缀,后面为二维码的参数值
       * 
       * 用户已关注时的事件推送
       * Event    事件类型,SCAN
       * EventKey 事件KEY值,是一个32位无符号整数,即创建二维码时的二维码scene_id
       */
      @XmlRootElement
      public class MsgScanCodeEvent extends MsgBaseEvent {
      
          @XmlElement(name = "EventKey")
          private String EventKey;    //事件KEY值,qrscene_为前缀,后面为二维码的参数值 
      
          @XmlElement(name = "Ticket")
          private String Ticket;      //二维码的ticket,可用来换取二维码图片
      
          public String getEventKey() {
              return EventKey;
          }
          public void setEventKey(String eventKey) {
              EventKey = eventKey;
          }
      
          public String getTicket() {
              return Ticket;
          }
          public void setTicket(String ticket) {
              Ticket = ticket;
          }
      
          /*
           * 接收到的文本示例
           * <xml>
           *  <ToUserName><![CDATA[toUser]]></ToUserName>
           *  <FromUserName><![CDATA[FromUser]]></FromUserName>
           *  <CreateTime>123456789</CreateTime>
           *  <MsgType><![CDATA[event]]></MsgType>
           *  <Event><![CDATA[subscribe|SCAN]]></Event>
           *  <EventKey><![CDATA[qrscene_123123|SCENE_VALUE]]></EventKey>
           *  <Ticket><![CDATA[TICKET]]></Ticket>
           * </xml>
           */
          public static MsgScanCodeEvent requestMessage(String xmlStr) throws JAXBException {
              xmlStr = xmlStr.replace("xml", "msgScanCodeEvent");
              JAXBContext context = JAXBContext.newInstance(MsgScanCodeEvent.class);  
              Unmarshaller unmarshaller = context.createUnmarshaller();  
              return (MsgScanCodeEvent)unmarshaller.unmarshal(new StringReader(xmlStr));
          }
      }

    上报地理位置事件

    用户同意上报地理位置后,每次进入公众号会话时,都会在进入时上报地理位置,或在进入会话后每5秒上报一次地理位置,公众号可以在公众平台网站中修改以上设置。上报地理位置时,微信会将上报地理位置事件推送到开发者填写的URL。

    /*
     * Event--->
     * LOCATION
     */
    @XmlRootElement
    public class MsgLocationEvent extends MsgBaseEvent {
    
        @XmlElement(name = "Latitude") 
        private float Latitude;     //地理位置纬度
    
        @XmlElement(name = "Longitude") 
        private float Longitude;    //地理位置经度
    
        @XmlElement(name = "Precision") 
        private float Precision;    //地理位置精度
    
        public float getLatitude() {
            return Latitude;
        }
        public void setLatitude(float latitude) {
            Latitude = latitude;
        }
    
        public float getLongitude() {
            return Longitude;
        }
        public void setLongitude(float longitude) {
            Longitude = longitude;
        }
    
        public float getPrecision() {
            return Precision;
        }
        public void setPrecision(float precision) {
            Precision = precision;
        }
    
        /*
         * 接收到的文本示例
         * <xml>
         *   <ToUserName><![CDATA[toUser]]></ToUserName>
         *   <FromUserName><![CDATA[fromUser]]></FromUserName>
         *   <CreateTime>1348831860</CreateTime>
         *   <MsgType><![CDATA[event]]></MsgType>
         *   <Event><![CDATA[LOCATION]]></Event>
         *   <Latitude>23.137466</Latitude>
         *   <Longitude>113.352425</Longitude>
         *   <Precision>119.385040</Precision>
         * </xml>
         */
        public static MsgLocationEvent requestMessage(String xmlStr) throws JAXBException {
            xmlStr = xmlStr.replace("xml", "msgLocationEvent");
            JAXBContext context = JAXBContext.newInstance(MsgLocationEvent.class);  
            Unmarshaller unmarshaller = context.createUnmarshaller();  
            return (MsgLocationEvent)unmarshaller.unmarshal(new StringReader(xmlStr));
        }
    }

    自定义菜单事件

    用户点击自定义菜单后,微信会把点击事件推送给开发者,请注意,点击菜单弹出子菜单,不会产生上报。

    点击菜单拉取消息时的事件推送

    /*
     * Event--->
     * click:点击菜单拉取消息时的事件推送
     */
    @XmlRootElement
    public class MenuClickEvent extends MenuBaseEvent {
    
        /*
         * 接收到的文本示例
         * <xml>
         *  <ToUserName><![CDATA[toUser]]></ToUserName>
         *  <FromUserName><![CDATA[FromUser]]></FromUserName>
         *  <CreateTime>123456789</CreateTime>
         *  <MsgType><![CDATA[event]]></MsgType>
         *  <Event><![CDATA[CLICK]]></Event>
         *  <EventKey><![CDATA[EVENTKEY]]></EventKey>
         * </xml>
         */
        public static MenuClickEvent requestMessage(String xmlStr) throws JAXBException {
            xmlStr = xmlStr.replace("xml", "menuClickEvent");
            JAXBContext context = JAXBContext.newInstance(MenuClickEvent.class);  
            Unmarshaller unmarshaller = context.createUnmarshaller();  
            return (MenuClickEvent)unmarshaller.unmarshal(new StringReader(xmlStr));
        }
    }

    点击菜单跳转链接时的事件推送

    /*
     * Event--->
     * view:点击菜单跳转链接时的事件推送
     */
    @XmlRootElement
    public class MenuViewEvent extends MenuBaseEvent {
    
        @XmlElement(name = "MenuId")  
        private String MenuId ;         //指菜单ID,如果是个性化菜单,则可以通过这个字段,知道是哪个规则的菜单被点击了。
    
        public String getMenuId() {
            return MenuId;
        }
        public void setMenuId(String menuId) {
            MenuId = menuId;
        }
    
        /*
         * 接收到的文本示例
         * <xml>
         *  <ToUserName><![CDATA[toUser]]></ToUserName>
         *  <FromUserName><![CDATA[FromUser]]></FromUserName>
         *  <CreateTime>123456789</CreateTime>
         *  <MsgType><![CDATA[event]]></MsgType>
         *  <Event><![CDATA[VIEW]]></Event>
         *  <EventKey><![CDATA[www.qq.com]]></EventKey>
         *  <MenuId>MENUID</MenuId>
         * </xml>
         */
        public static MenuViewEvent requestMessage(String xmlStr) throws JAXBException {
            xmlStr = xmlStr.replace("xml", "menuViewEvent");
            JAXBContext context = JAXBContext.newInstance(MenuViewEvent.class);  
            Unmarshaller unmarshaller = context.createUnmarshaller();  
            return (MenuViewEvent)unmarshaller.unmarshal(new StringReader(xmlStr));
        }
    }
    展开全文
  • ​在微信用户和公众号产生交互的过程中,用户的某些操作会使得微信服务器通过事件推送的形式通知到开发者在开发者中心处设置的服务器地址,从而开发者可以获取到该信息。其中,某些事件推送在发生后,是允许开发者...
  • 用户点击自定义菜单后,微信会把点击事件推送给开发者,请注意,点击菜单弹出子菜单,不会产生上报。请注意,第3个到第8个的所有事件,仅支持微信iPhone5.4.1以上版本,和Android5.4以上版本的微信用户,旧版本微信...
  • 微信小程序开发说实话还是有点糟心的,经过事件冒泡的坑之后,又遇到了长按事件(longtap)必触发点击事件(tap)的BUG 实例代码 wxml <view class="container"> <view> <button bindtap="tap" ...
  • 微信小程序开发说实话还是有点糟心的,经过事件冒泡的坑之后,又遇到了长按事件(longtap)必触发点击事件(tap)的BUG 实例代码 wxml <view class="container"> <view> <button bindtap="tap" ...
  • 不过微信开发到现在也是老生常谈的的东西了,我就简单写一下菜单事件推送的这个过程。 注意:点击菜单弹出子菜单,不会产生请求交互。 1.先来看下相应的接口参数及说明 参数 描述 ToUserName 开发者微信号 ...
  • 配置微信公众号当普通微信用户向公众号发送消息或者与微信公众号进行互动触发某些事件时,微信服务器将会把这些消息或者事件以XML数据包格式POST到开发者在微信公众号管理平台中配置的服务器地址URL上。
  • 在使用微信公众号过程中, 经常会与公众号的粉丝进行互动, 微信把一些重要的动作...众多的事件分布于整个微信开发过程, 像前面讲的菜单点击事件, 还有地理位置事件等等。 在这个系列中, 我们着重讲
  • 上一篇《微信开发学习总结(一)——微信开发环境搭建》我们已经完成了微信开发的准备工作,准备工作完成之后,就要开始步入正题了。 一、微信公众平台的基本原理  在开始做之前,先简单介绍了微信公众平台的基本...
  • 微信开发时候在做消息接口交互的时候需要使用带微信加密ID(OpenId),下面讲讲述2中类型方式获取微信OpenID,接收事件推送方式和网页授权获取用户基本信息方式获取。
  • **!... # 如图 **像流利说微信公众号一样** ...**根据点击了菜单不同的 发送过来的消息进行不同的处理** **例子的公众号是** ![图片说明](https://img-ask.csdn.net/upload/201612/22/1482413246_315107.jpg)**
  • 微信公众号开发(6)关注事件 学习目标 推送 event subscribe(关注) unsubscribe(取消关注) CLICK (自定义菜单点击事件) 关键代码如下: $ev = $postObj-&gt;Event; if ($ev == "subscribe&...
  • 公众号运营者发送模板消息的时候需要有模板和template_id,不同类别的模板有不同的template_id调用微信模板消息接口发模板消息的时候,如果可以成功发送出去,则会返回一个json数据包, 数据包里有msgid,如果消息...
  • 事件处理是非常重要的,这一章讲讲常见的事件处理 1、关注/取消关注 2、菜单点击 事件类型介绍: 在微信中有事件请求是消息请求中的一种。请求类型为:event 而event事件类型又分多种事件类型,具体分 ...
  •  开发环境参考:微信开发(一)--分享接口 点击打开链接 由于是基于weixin-java-tools 封装的java sdk,所以在微信底层处理上我们可以直接调用WxMpService. 一.数据准备: 进入页面前,根据条件查询相应的图片...
  • 昨天在微信开发平台官网下了微信开发小程序软件(.exe 64位),在自己台式机(windows 7 系统,64位)上安装可以正常打开运行,但在自己笔记本(windows 10 ,64位)上,安装以后,点击无任何反应。 然后上网查资料...
  • 接收到的消息和事件,其实都是微信post到我们配置的URL的消息。接收普通消息就是用户给公众号发送的消息,事件是由于用户的特定操作,微信post给我们的消息。被动响应消息是我们收到微信post过来的普通消息或者是...
1 2 3 4 5 ... 20
收藏数 50,209
精华内容 20,083
关键字:

微信开发处理点击事件