微信公众账号开发简单实例【java】

来源:互联网 发布:李升平知乎 编辑:程序博客网 时间:2024/05/29 10:43

进入公众账号的后台https://mp.weixin.qq.com/, 

微信公众平台的通讯机制


开发流程


从上图中可以看到,高级功能包含两种模式:编辑模式和开发模式,并且这两种模式是互斥关系,即两种模式不能同时开启。那两种模式有什么区别呢?作为开发人员到底要开启哪一种呢?

编辑模式:主要针对非编程人员及信息发布类公众帐号使用。开启该模式后,可以方便地通过界面配置“自定义菜单”和“自动回复的消息”。

开发模式:主要针对具备开发能力的人使用。开启该模式后,能够使用微信公众平台开放的接口,通过编程方式实现自定义菜单的创建、用户消息的接收/处理/响应。这种模式更加灵活,建议有开发能力的公司或个人都采用该模式。

在这里就只介绍开发模式了, 编辑没有就不用讲了,都是动手操作的事情太简单了。 嘿嘿。


开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,否则接入失败。

signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。

加密/校验流程:1. 将token、timestamp、nonce三个参数进行字典序排序2. 将三个参数字符串拼接成一个字符串进行sha1加密3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信

备注 :URL必须是公网地址


后台代码

[java] view plain copy
  1. /** 
  2.  * User: zhanglin 
  3.  * Date: 13-10-23 
  4.  * Time: 下午5:31 
  5.  * Desc: 微信控制电器 
  6.  */  
  7. @Controller  
  8. @RequestMapping("/")  
  9. public class WeiXinControllerTest {  
  10.     private static Logger log = LogManager.getLogger(WeiXinControllerTest.class);  
  11.     @Resource  
  12.     private ServiceConfig serviceConfig;  
  13.     @Resource  
  14.     private IWeiXinTextService weiXinTextService;  
  15.     //get请求方式,可以做测试用。  
  16.     @ResponseBody  
  17.     @RequestMapping(method = RequestMethod.GET)  
  18.     public String get(ModelMap model, String signature, String timestamp, String nonce, String echostr) {  
  19.         boolean bChecked = check(signature, timestamp, nonce);  
  20.         if (bChecked) {  
  21.             return echostr;  
  22.         }  
  23.         return "hello";  
  24.     }                                                                                                                                   //微信进来的请求就通过POST方式进来  
  25.     @RequestMapping(method = RequestMethod.POST)  
  26.     public void post(String signature, String timestamp, String nonce, HttpServletRequest request, HttpServletResponse response) {  
  27.         boolean bChecked = check(signature, timestamp, nonce);  
  28.         if (bChecked) {  
  29.             response.setCharacterEncoding("UTF-8");  
  30.             PrintWriter out = null;  
  31.             Document doc;  
  32.             SAXReader reader = new SAXReader();  
  33.             InputStream in = null;  
  34.             try {  
  35.                 out = response.getWriter();  
  36.                 in = request.getInputStream();  
  37.                 doc = reader.read(in);  
  38.                 Element root = doc.getRootElement();  
  39.                 //根据消息类型执行不同的方法  
  40.                 checkMsgType(out, root,response);  
  41.             } catch (Exception e) {  
  42.                 log.debug(e.getMessage());  
  43.             } finally {  
  44.                 if (in != null) {  
  45.                     try {  
  46.                         in.close();  
  47.                     } catch (IOException e) {  
  48.                         log.debug(e.getMessage());  
  49.                     }  
  50.                 }  
  51.                 if (out != null) {  
  52.                     out.flush();  
  53.                     out.close();  
  54.                 }  
  55.             }  
  56.         }  
  57.   
  58.     }  
  59.   
  60.     /** 
  61.      * 检测是否为微信发送的请求 
  62.      * 
  63.      * @param signature 
  64.      * @param timestamp 
  65.      * @param nonce 
  66.      * @return 
  67.      */  
  68.     private boolean check(String signature, String timestamp, String nonce) {  
  69.         List<String> strList = new ArrayList<String>();                                                                                     //这里的token 就是网站填的值, 建议用配置文件读取,根据环境不同读取不同的数据。   
  70.         strList.add(serviceConfig.getToken());  
  71.         strList.add(timestamp);  
  72.         strList.add(nonce);  
  73.         Collections.sort(strList);  
  74.         String str = "";  
  75.         for (String s : strList) {  
  76.             str += s;  
  77.         }  
  78.         String strSha = DigestUtils.shaHex(str);  
  79.         return strSha.equals(signature);  
  80.     }  
  81. }  

微信向公众号发送一个地理位置,然后公众号读取坐标 ,查询这个坐标附近的数据。


     当用户向公众号发送请求, 微信服务器再向公众号发送的是XML的数据, 所以不了解解析XML,封装XML的童鞋可以先去补一下这方面的知识。


后台代码

//把抽象的东西抽取成java对象

[java] view plain copy
  1. /** 
  2.  * User: zhanglin 
  3.  * Date: 13-10-23 
  4.  * Time: 下午4:26 
  5.  */  
  6. public enum MsgType {  
  7.     text("文本"),image("图片"),location("地理位置"),link("连接"),event("事件"),news("图文信息") ;  
  8.     private String value;  
  9.   
  10.     public String getValue() {  
  11.         return value;  
  12.     }  
  13.   
  14.     private MsgType(String value) {  
  15.         this.value = value;  
  16.     }  
  17. }  
封装图文消息类,在这里笔者是用xml提供的标签来创建xml

[java] view plain copy
  1. import javax.xml.bind.annotation.XmlElement;  
  2. import javax.xml.bind.annotation.XmlRootElement;  
  3.   
  4. /** 
  5.  * User: zhanglin 
  6.  * Date: 13-10-24 
  7.  * Time: 下午1:37 
  8.  * desc: 图片文消息 
  9.  */  
  10. @XmlRootElement(name="item")  
  11. public class Item {  
  12.     private String title;  
  13.     private String description;  
  14.     private String picUrl;  
  15.     private String url;  
  16.   
  17.     public Item() {  
  18.     }  
  19.   
  20.     public Item(String title, String description, String picUrl, String url) {  
  21.         this.title = title;  
  22.         this.description = description;  
  23.         this.picUrl = picUrl;  
  24.         this.url = url;  
  25.     }  
  26.     @XmlElement(name = "Title")  
  27.     public String getTitle() {  
  28.         return title;  
  29.     }  
  30.   
  31.     public void setTitle(String title) {  
  32.         this.title = title;  
  33.     }  
  34.     @XmlElement(name = "Description")  
  35.     public String getDescription() {  
  36.         return description;  
  37.     }  
  38.   
  39.     public void setDescription(String description) {  
  40.         this.description = description;  
  41.     }  
  42.     @XmlElement(name = "PicUrl")  
  43.     public String getPicUrl() {  
  44.         return picUrl;  
  45.     }  
  46.   
  47.     public void setPicUrl(String picUrl) {  
  48.         this.picUrl = picUrl;  
  49.     }  
  50.     @XmlElement(name = "Url")  
  51.     public String getUrl() {  
  52.         return url;  
  53.     }  
  54.   
  55.     public void setUrl(String url) {  
  56.         this.url = url;  
  57.     }  
  58. }  

//查询坐标附近的数据

[java] view plain copy
  1. /** 
  2.   * 根据不同的类型执行不同的方法 
  3.   * 
  4.   * @param out  输出流 
  5.   * @param root 从请求中获得的有关xml对象 
  6.   */  
  7.  private void checkMsgType(PrintWriter out, Element root) {  
  8.      try {  
  9.          String value = root.element("MsgType").getTextTrim();  
  10.          //<span style="font-family: Arial; font-size: 14px; line-height: 26px;">查询坐标附近的数据</span>  
  11.          if (MsgType.location.toString().equals(value)) {  
  12.              findNearCommunity(out, root);  
  13.          }  
  14.   
  15.          //做其他的逻辑  
  16.      } catch (Exception e) {  
  17.          log.debug(e.getMessage());  
  18.      }  
  19.  }  

[java] view plain copy
  1. /** 
  2.   
  3.  * 
  4.  * @param out 
  5.  * @param root 
  6.  */  
  7. private void findNearCommunity(PrintWriter out, Element root) throws Exception {  
  8.     NearCoordinate nearCoordinate = param(root);  
  9.     Integer count ="..." ;//调用接口查询条数  
  10.     List<Object> list = "...";//调用接口查询数据  
  11.     out.println(WeiXinXmlFactory.getImgNewsXml(list, root, count));  
  12. }  
[java] view plain copy
  1. <span style="font-size: 14px;">    /** 
  2.      * 图文信息xml 
  3.      * @param list 结果集 
  4.      * @param root 
  5.      * @param count 总条数 
  6.      * @return 
  7.      */  
  8.     public static  String  getImgNewsXml(List<CommunityDto> list,Element root,Integer count) {  
  9.         try {                                                                                                                                                         //接收方帐号(收到的OpenID)  
  10.             String toUserName = root.element("ToUserName").getTextTrim();                                                                                             // 开发者微信号   
  11.             String fromUserName = root.element("FromUserName").getTextTrim();  
  12.             Marshaller m = getMarshaller(new WeiXinImg());  
  13.             ArrayList<Item> items = new ArrayList<Item>();  
  14.             Articles articles = new Articles();  
  15.             Item item ;  
  16.             int next=0;  
  17.             for (CommunityDto communityDto:list){  
  18.                 //封装 Item对象  
  19.                 items.add(item);  
  20.                 next++;  
  21.             }  
  22.             //总条数大于列表条数  
  23.             if(WeiXinConfig.COMMUNITY_LIST_SIZE<count){  
  24.                //封装一个“更多” Item对象  
  25.                 items.add(item);  
  26.             }  
  27.             articles.setArrayList(items);  
  28.             WeiXinImg weiXinImg = new WeiXinImg(fromUserName,toUserName,System.currentTimeMillis(), MsgType.news,<span style="font-family: Arial, Helvetica, sans-serif;">count</span><span style="font-family: Arial, Helvetica, sans-serif;">,articles);</span>  
  29.             StringWriter fw = new StringWriter();  
  30.             m.marshal(weiXinImg, fw);  
  31.             return fw.toString();  
  32.         }catch (Exception e){  
  33.            log.debug(e.getMessage());  
  34.         }  
  35.         return  null;  
  36.   
  37.   
  38.     }  


//创建一个< tt >Marshaller< / tt >对象,可以用来转换成一个Java内容树转换成XML数据

[java] view plain copy
  1. private  static Marshaller getMarshaller(Object o)throws  Exception{  
  2.         JAXBContext context = JAXBContext.newInstance(o.getClass());  
  3.         // 下面代码演示将对象转变为xml  
  4.         Marshaller m = context.createMarshaller();  
  5.         //是否格式化生成的xml串  
  6.         m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, false);  
  7.         //是否省略xml头信息  
  8.         m.setProperty(Marshaller.JAXB_FRAGMENT, true);  
  9.         return  m;  
  10.     }  



[java] view plain copy
  1. /** 
  2.     * 图文信息xml 
  3.     * @param list 结果集 
  4.     * @param root 
  5.     * @param count 总条数 
  6.     * @return 
  7.     */  
  8.    public static  String  getImgNewsXml(List<CommunityDto> list,Element root,Integer count) {  
  9.        try {  
  10.            String toUserName = root.element("ToUserName").getTextTrim();  
  11.            String fromUserName = root.element("FromUserName").getTextTrim();  
  12.            Marshaller m = getMarshaller(new WeiXinImg());  
  13.            ArrayList<Item> items = new ArrayList<Item>();  
  14.            Articles articles = new Articles();  
  15.            Item item ;  
  16.            int next=0;  
  17.            for (CommunityDto communityDto:list){  
  18.               //组装Item对象  
  19.                items.add(item);  
  20.                next++;  
  21.            }  
  22.            //总条数大于列表条数  
  23.            if(WeiXinConfig.COMMUNITY_LIST_SIZE<count){  
  24.                item = new Item("更多","",WeiXinConfig.FUNI_LOGO,UrlGenerator.getWapCommunityList(WeiXinConfig.CITY));  
  25.                items.add(item);  
  26.            }  
  27.            articles.setArrayList(items);  
  28.            int articleCount = itemCount(list.size(),WeiXinConfig.COMMUNITY_LIST_SIZE<count);  
  29.            WeiXinImg weiXinImg = new WeiXinImg(fromUserName,toUserName,System.currentTimeMillis(), MsgType.news,articleCount,articles);  
  30.            StringWriter fw = new StringWriter();  
  31.            m.marshal(weiXinImg, fw);  
  32.            return fw.toString();  
  33.        }catch (Exception e){  
  34.           log.debug(e.getMessage());  
  35.        }  
  36.        return  null;  
  37.   
  38.    }  


//运行的结果

原创粉丝点击