微信公众平台开发教程Java版(1)环境准备篇

微信公众平台开发教程Java版(一)环境准备篇

准备写系列博客,记录下我的微信公众平台学习记录,也为那些摸索中的开发者提供点参考。

希望与大家共同进步。

微信3.0的时候我开始做微信公众账号,那时候没时间研究开发,先用的是编辑者模式,后用开发者模式,托管于第三方。

一直想自己写个服务端来实现个人定制化的需求。

废话不多说,进入正题。

想要开发微信公众平台需要一些环境

一、申请微信公众账号

这个就不用废话了。附上地址:
       https://mp.weixin.qq.com/cgi-bin/readtemplate?t=wxm2-realname-reg_tmpl&lang=zh_CN
       现在申请好严格的说,3.0的时候申请都不需要拍照什么的。

友情提示:
                 1、微信公众账号的名字一旦申请,则不能更改。取名请慎重!

2、一个身份证只能申请两个公众号

3、公众号分两种:订阅号和服务号

订阅号可一天群发一次消息,目前不能申请自定义菜单。发送的消息将显示在“订阅号”文件夹中,适合媒体等提供咨询服务的公众号。

服务号一个月只能群发一条消息,能申请自定义菜单,发送的消息会显示在用户的聊天列表中,并会提醒用户新消息。适合为用户提供服务的公众号

二、外网服务器

你需要一台外网服务器,来发布你的代码,用于接收处理用户发送的请求。

如果没有的话,也不用担心。可以使用百度BAE,或者是sina sae,国外比较多的是用google的gae。

google gae支持的语言很多。但是在国内经常访问不了,不推荐使用。

百度Bae 支持java和php(完全免费,百度对于资源方面还是一向很大方的,赞一个,哈哈)

sina sae 支持java,php,python(可免费使用半年,收费的,但很便宜)

三、至少会一种语言
        java,php,asp,python等,至少得会一样!

微信公众平台开发教程Java版(2)接口配置

微信公众账号申请完成后,默认开启的是编辑模式。

我们需要修改为开发模式。

登陆微信公众平台》功能》高级功能

先关闭 编辑模式,再开启 开发模式。

申请成为开发者,如果是服务号,需要则会有开发者凭证信息

如图

如果是订阅号,则只显示服务器配置。

下一步就是配置接口服务器了。

在公众平台网站的高级功能 – 开发模式页,点击“成为开发者”按钮,填写URL和Token,其中URL是开发者用来接收微信服务器数据的接口URL。(这就是我们开发的程序,并部署到公网上了)

Token 官网描述:可由开发者任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)。

总之就是你的程序里面写的token和这里填入的token要一致。

还没有url和token?

首先需要新建一个java web工程。

接下来就要看看验证url和token了。

下面是官网的描述,已经写的很清楚了


 核心实现方式就是将三个参数排序,拼接成字符串进行sha1加密,然后与signature比较

官网也给了实例,是php的,我们只需要装换成java就可以了。

private function checkSignature()
{$signature = $_GET["signature"];$timestamp = $_GET["timestamp"];$nonce = $_GET["nonce"];  $token = TOKEN;$tmpArr = array($token, $timestamp, $nonce);sort($tmpArr);$tmpStr = implode( $tmpArr );$tmpStr = sha1( $tmpStr );if( $tmpStr == $signature ){return true;}else{return false;}
}

java代码 我的 WeixinController 类

我的项目架构是基于spring3.0的,用到了注解。当get请求的时候会执行get方法,post请求的时候会执行post方法,分别来处理不同的请求,各位也可用servlet等去实现,原理都一样

package com.ifp.weixin.controller;import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;import com.ifp.weixin.biz.core.CoreService;
import com.ifp.weixin.util.SignUtil;@Controller
@RequestMapping("/weixinCore")
public class WeixinController {@Resource(name="coreService")private CoreService coreService;@RequestMapping(method = RequestMethod.GET)public void get(HttpServletRequest request, HttpServletResponse response) {// 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。String signature = request.getParameter("signature");// 时间戳String timestamp = request.getParameter("timestamp");// 随机数String nonce = request.getParameter("nonce");// 随机字符串String echostr = request.getParameter("echostr");PrintWriter out = null;try {out = response.getWriter();// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,否则接入失败if (SignUtil.checkSignature(signature, timestamp, nonce)) {out.print(echostr);}} catch (IOException e) {e.printStackTrace();} finally {out.close();out = null;}}@RequestMapping(method = RequestMethod.POST)public void post(HttpServletRequest request, HttpServletResponse response) {//暂时空着,在这里可处理用户请求}}

上面类中用到了SignUtil 类

package com.ifp.weixin.util;import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;import com.ifp.weixin.constant.Constant;
/*** 验证签名**/
public class SignUtil {/*** 验证签名* @param signature* @param timestamp* @param nonce* @return*/public static boolean checkSignature(String signature, String timestamp, String nonce) {String[] arr = new String[] { Constant.TOKEN, timestamp, nonce };// 将token、timestamp、nonce三个参数进行字典排序Arrays.sort(arr);StringBuilder content = new StringBuilder();for (int i = 0; i < arr.length; i++) {content.append(arr[i]);}MessageDigest md = null;String tmpStr = null;try {md = MessageDigest.getInstance("SHA-1");// 将三个参数字符串拼接成一个字符串进行sha1加密byte[] digest = md.digest(content.toString().getBytes());tmpStr = byteToStr(digest);} catch (NoSuchAlgorithmException e) {e.printStackTrace();}content = null;// 将sha1加密后的字符串可与signature对比return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;}/*** 将字节数组转换为十六进制字符串* * @param byteArray* @return*/private static String byteToStr(byte[] byteArray) {String strDigest = "";for (int i = 0; i < byteArray.length; i++) {strDigest += byteToHexStr(byteArray[i]);}return strDigest;}/*** 将字节转换为十六进制字符串* * @param mByte* @return*/private static String byteToHexStr(byte mByte) {char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };char[] tempArr = new char[2];tempArr[0] = Digit[(mByte >>> 4) & 0X0F];tempArr[1] = Digit[mByte & 0X0F];String s = new String(tempArr);return s;}
}

我们看到 checkSignature 这个方法里使用到了Constant.TOKEN ,这个token,我声明的一个常量。

要与微信配置接口里面的token值一样

/**
* 与接口配置信息中的Token要一致
*/
public static String TOKEN = "infopower";

也贴上web.xml的配置,我的后缀是.html 的请求都交给DispatcherServlet了。

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"><display-name>weixinHelp</display-name><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:/applicationContext.xml</param-value></context-param><context-param><param-name>log4jConfigLocation</param-name><param-value>classpath:/properties/log4j.properties</param-value></context-param><listener><listener-class>org.springframework.web.util.Log4jConfigListener</listener-class></listener><filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><listener><description>spring 容器的监听器</description><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><servlet><servlet-name>action</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class></servlet><servlet-mapping><servlet-name>action</servlet-name><url-pattern>*.html</url-pattern></servlet-mapping><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list>
</web-app>

我们的代码已经写完了,访问请求地址试试

什么都没有显示,看看后台

报空指针异常

别担心,我们的代码没问题。

因为直接访问地址,默认是get请求,而什么参数都没有传给后台,当然会报空指针

前台没有异常,是因为我做了异常处理。

ok

接下来就是把代码打成war包发布到外网。

然后填入相应的url和token,接口的配置就完成了。

注意1:一定要发布war包到外网,配置外网的url,有些开发者配置的是ip是localhost,那肯定是不行的啦。

如果没有外网环境,请看我的第一篇,环境准备,里面有介绍可以使用百度bae

http://tuposky.iteye.com/blog/2008583

注意2:开发模式一定要开启,不然配置了url和token也没用,我犯过这个错,嘿嘿。

微信公众平台开发教程Java版(3) 消息接收和发送

微信公众平台开发教程Java版(三) 消息接收和发送

前面两章已经介绍了如何接入微信公众平台,这一章说说消息的接收和发送

可以先了解公众平台的消息api接口(接收消息,发送消息)

http://mp.weixin.qq.com/wiki/index.php

接收消息

当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。

http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF

接收的消息类型有6种,分别为:

  • 1 文本消息
  • 2 图片消息
  • 3 语音消息
  • 4 视频消息
  • 5 地理位置消息
  • 6 链接消息

可以根据官方的api提供的字段建立对应的实体类

如:文本消息

有很多属性是所有消息类型都需要的,可以把这些信息提取出来建立一个基类

package com.ifp.weixin.entity.Message.req;/*** 消息基类(用户 -> 公众帐号)* */
public class BaseMessage {/*** 开发者微信号*/private String ToUserName;/*** 发送方帐号(一个OpenID)*/private String FromUserName;/*** 消息创建时间 (整型)*/private long CreateTime;/*** 消息类型 text、image、location、link*/private String MsgType;/*** 消息id,64位整型*/private long MsgId;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;}public long getMsgId() {return MsgId;}public void setMsgId(long msgId) {MsgId = msgId;}}

接收的文本消息

package com.ifp.weixin.entity.Message.req;/*** 文本消息*/
public class TextMessage extends BaseMessage {/*** 回复的消息内容*/private String Content;public String getContent() {return Content;}public void setContent(String content) {Content = content;}
}

接收的图片消息

package com.ifp.weixin.entity.Message.req;public class ImageMessage extends BaseMessage{private String picUrl;public String getPicUrl() {return picUrl;}public void setPicUrl(String picUrl) {this.picUrl = picUrl;}}

接收的链接消息

package com.ifp.weixin.entity.Message.req;public class LinkMessage extends BaseMessage {/*** 消息标题*/private String Title;/*** 消息描述*/private String Description;/*** 消息链接*/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 getUrl() {return Url;}public void setUrl(String url) {Url = url;}}

接收的语音消息

package com.ifp.weixin.entity.Message.req;/*** 语音消息* * @author Caspar* */
public class VoiceMessage extends BaseMessage {/*** 媒体ID*/private String MediaId;/*** 语音格式*/private String Format;public String getMediaId() {return MediaId;}public void setMediaId(String mediaId) {MediaId = mediaId;}public String getFormat() {return Format;}public void setFormat(String format) {Format = format;}}

接收的地理位置消息

package com.ifp.weixin.entity.Message.req;/*** 位置消息* * @author caspar* */
public class LocationMessage extends BaseMessage {/*** 地理位置维度*/private String Location_X;/*** 地理位置经度*/private String Location_Y;/*** 地图缩放大小*/private String Scale;/*** 地理位置信息*/private String Label;public String getLocation_X() {return Location_X;}public void setLocation_X(String location_X) {Location_X = location_X;}public String getLocation_Y() {return Location_Y;}public void setLocation_Y(String location_Y) {Location_Y = location_Y;}public String getScale() {return Scale;}public void setScale(String scale) {Scale = scale;}public String getLabel() {return Label;}public void setLabel(String label) {Label = label;}}

发送被动响应消息

对于每一个POST请求,开发者在响应包(Get)中返回特定XML结构,对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。请注意,回复图片等多媒体消息时需要预先上传多媒体文件到微信服务器,只支持认证服务号。

同样,建立响应消息的对应实体类

也把公共的属性提取出来,封装成基类

响应消息的基类

package com.ifp.weixin.entity.Message.resp;/*** 消息基类(公众帐号 -> 用户)*/
public class BaseMessage {/*** 接收方帐号(收到的OpenID)*/private String ToUserName;/*** 开发者微信号*/private String FromUserName;/*** 消息创建时间 (整型)*/private long CreateTime;/*** 消息类型*/private String MsgType;/*** 位0x0001被标志时,星标刚收到的消息*/private int FuncFlag;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;}public int getFuncFlag() {return FuncFlag;}public void setFuncFlag(int funcFlag) {FuncFlag = funcFlag;}
}

响应文本消息

package com.ifp.weixin.entity.Message.resp;/*** 文本消息*/
public class TextMessage extends BaseMessage {/*** 回复的消息内容*/private String Content;public String getContent() {return Content;}public void setContent(String content) {Content = content;}
}

响应图文消息

package com.ifp.weixin.entity.Message.resp;import java.util.List;/*** 多图文消息,* 单图文的时候 Articles 只放一个就行了* @author Caspar.chen*/
public class NewsMessage extends BaseMessage {/*** 图文消息个数,限制为10条以内*/private int ArticleCount;/*** 多条图文消息信息,默认第一个item为大图*/private List<Article> Articles;public int getArticleCount() {return ArticleCount;}public void setArticleCount(int articleCount) {ArticleCount = articleCount;}public List<Article> getArticles() {return Articles;}public void setArticles(List<Article> articles) {Articles = articles;}
}

图文消息的定义

package com.ifp.weixin.entity.Message.resp;/*** 图文消息* */
public class Article {/*** 图文消息名称*/private String Title;/*** 图文消息描述*/private String Description;/*** 图片链接,支持JPG、PNG格式,<br>* 较好的效果为大图640*320,小图80*80*/private String PicUrl;/*** 点击图文消息跳转链接*/private String Url;public String getTitle() {return Title;}public void setTitle(String title) {Title = title;}public String getDescription() {return null == Description ? "" : Description;}public void setDescription(String description) {Description = description;}public String getPicUrl() {return null == PicUrl ? "" : PicUrl;}public void setPicUrl(String picUrl) {PicUrl = picUrl;}public String getUrl() {return null == Url ? "" : Url;}public void setUrl(String url) {Url = url;}}

响应音乐消息

package com.ifp.weixin.entity.Message.resp;/*** 音乐消息*/
public class MusicMessage extends BaseMessage {/*** 音乐*/private Music Music;public Music getMusic() {return Music;}public void setMusic(Music music) {Music = music;}
}

音乐消息的定义

package com.ifp.weixin.entity.Message.resp;/*** 音乐消息*/
public class Music {/*** 音乐名称*/private String Title;/*** 音乐描述*/private String Description;/*** 音乐链接*/private String MusicUrl;/*** 高质量音乐链接,WIFI环境优先使用该链接播放音乐*/private String HQMusicUrl;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 getMusicUrl() {return MusicUrl;}public void setMusicUrl(String musicUrl) {MusicUrl = musicUrl;}public String getHQMusicUrl() {return HQMusicUrl;}public void setHQMusicUrl(String musicUrl) {HQMusicUrl = musicUrl;}}

构建好之后的项目结构图为

到这里,请求消息和响应消息的实体类都定义好了

解析请求消息

用户向微信公众平台发送消息后,微信公众平台会通过post请求发送给我们。

上一章中WeixinController 类的post方法我们空着

现在我们要在这里处理用户请求了。

因为微信的发送和接收都是用xml格式的,所以我们需要处理请求过来的xml格式。

发送的时候也需要转化成xml格式再发送给微信,所以封装了消息处理的工具类,用到dome4j和xstream两个jar包

package com.ifp.weixin.util;import java.io.InputStream;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;import com.ifp.weixin.entity.Message.resp.Article;
import com.ifp.weixin.entity.Message.resp.MusicMessage;
import com.ifp.weixin.entity.Message.resp.NewsMessage;
import com.ifp.weixin.entity.Message.resp.TextMessage;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;/*** 消息工具类* */
public class MessageUtil {/*** 解析微信发来的请求(XML)* * @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();// 得到根元素的所有子节点@SuppressWarnings("unchecked")List<Element> elementList = root.elements();// 遍历所有子节点for (Element e : elementList)map.put(e.getName(), e.getText());// 释放资源inputStream.close();inputStream = null;return map;}/*** 文本消息对象转换成xml* * @param textMessage 文本消息对象* @return xml*/public static String textMessageToXml(TextMessage textMessage) {xstream.alias("xml", textMessage.getClass());return xstream.toXML(textMessage);}/*** 音乐消息对象转换成xml* * @param musicMessage 音乐消息对象* @return xml*/public static String musicMessageToXml(MusicMessage musicMessage) {xstream.alias("xml", musicMessage.getClass());return xstream.toXML(musicMessage);}/*** 图文消息对象转换成xml* * @param newsMessage 图文消息对象* @return xml*/public static String newsMessageToXml(NewsMessage newsMessage) {xstream.alias("xml", newsMessage.getClass());xstream.alias("item", new Article().getClass());return xstream.toXML(newsMessage);}/*** 扩展xstream,使其支持CDATA块* */private static XStream xstream = new XStream(new XppDriver() {public HierarchicalStreamWriter createWriter(Writer out) {return new PrettyPrintWriter(out) {// 对所有xml节点的转换都增加CDATA标记boolean cdata = true;protected void writeText(QuickWriter writer, String text) {if (cdata) {writer.write("<![CDATA[");writer.write(text);writer.write("]]>");} else {writer.write(text);}}};}});}

接下来在处理业务逻辑,建立一个接收并响应消息的service类,并针对用户输入的1或2回复不同的信息给用户

package com.ifp.weixin.biz.core.impl;import java.util.Date;
import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;import com.ifp.weixin.biz.core.CoreService;
import com.ifp.weixin.constant.Constant;
import com.ifp.weixin.entity.Message.resp.TextMessage;
import com.ifp.weixin.util.MessageUtil;@Service("coreService")
public class CoreServiceImpl implements CoreService{public static Logger log = Logger.getLogger(CoreServiceImpl.class);@Overridepublic String processRequest(HttpServletRequest request) {String respMessage = null;try {// 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(Constant.RESP_MESSAGE_TYPE_TEXT);textMessage.setFuncFlag(0);// 文本消息if (msgType.equals(Constant.REQ_MESSAGE_TYPE_TEXT)) {// 接收用户发送的文本消息内容String content = requestMap.get("Content");if ("1".equals(content)) {textMessage.setContent("1是很好的");// 将文本消息对象转换成xml字符串respMessage = MessageUtil.textMessageToXml(textMessage);}else if ("2".equals(content)) {textMessage.setContent("我不是2货");// 将文本消息对象转换成xml字符串respMessage = MessageUtil.textMessageToXml(textMessage);}} } catch (Exception e) {e.printStackTrace();}return respMessage;}}

接下来在controller里面的post方法里面调用即可

WeixinController类的完整代码

package com.ifp.weixin.controller;import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;import com.ifp.weixin.biz.core.CoreService;
import com.ifp.weixin.util.SignUtil;@Controller
@RequestMapping("/weixinCore")
public class WeixinController {@Resource(name="coreService")private CoreService coreService;@RequestMapping(method = RequestMethod.GET)public void get(HttpServletRequest request, HttpServletResponse response) {// 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。String signature = request.getParameter("signature");// 时间戳String timestamp = request.getParameter("timestamp");// 随机数String nonce = request.getParameter("nonce");// 随机字符串String echostr = request.getParameter("echostr");PrintWriter out = null;try {out = response.getWriter();// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,否则接入失败if (SignUtil.checkSignature(signature, timestamp, nonce)) {out.print(echostr);}} catch (IOException e) {e.printStackTrace();} finally {out.close();out = null;}}@RequestMapping(method = RequestMethod.POST)public void post(HttpServletRequest request, HttpServletResponse response) {try {request.setCharacterEncoding("UTF-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}response.setCharacterEncoding("UTF-8");// 调用核心业务类接收消息、处理消息String respMessage = coreService.processRequest(request);// 响应消息PrintWriter out = null;try {out = response.getWriter();out.print(respMessage);} catch (IOException e) {e.printStackTrace();} finally {out.close();out = null;}}}

效果如下:

ok,大功告成,消息的接收和发送就写完了。

微信公众平台开发教程Java版(4) 图文消息

微信公众平台开发教程Java版(四) 图文消息

引言:

上一章讲到了消息的接收和发送,但是讲的是最简单的文本信息。

在微信中用的最多的信息还是图文消息,本章就为大家讲解下微信图文消息是如何实现的。

包括单图文和多图文消息。

图文消息的XML数据包结构:

<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<ArticleCount>2</ArticleCount>
<Articles>
<item>
<Title><![CDATA[title1]]></Title>
<Description><![CDATA[description1]]></Description>
<PicUrl><![CDATA[picurl]]></PicUrl>
<Url><![CDATA[url]]></Url>
</item>
<item>
<Title><![CDATA[title]]></Title>
<Description><![CDATA[description]]></Description>
<PicUrl><![CDATA[picurl]]></PicUrl>
<Url><![CDATA[url]]></Url>
</item>
</Articles>
</xml>

从上面结构图中可以看出要注意的几点

1、图文消息的条数最大限制为10,

2、多图文中列表中的第一个为大图,其余为小图

注意:在多图文模式下只有第一个可以显示描述信息,其余的都不显示

了解了图文消息的结构后,要发送图文消息就简单了。

我们之前已经封装过消息处理的代码和图文消息的实体类,这里就不啰嗦了,不知道的可以看上一章

微信公众平台开发教程Java版(三) 消息接收和发送

下面我就上单图文和多图文消息的源代码

package com.ifp.weixin.biz.core.impl;import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;import com.ifp.weixin.biz.core.CoreService;
import com.ifp.weixin.constant.Constant;
import com.ifp.weixin.entity.Message.resp.Article;
import com.ifp.weixin.entity.Message.resp.NewsMessage;
import com.ifp.weixin.entity.Message.resp.TextMessage;
import com.ifp.weixin.util.MessageUtil;@Service("coreService")
public class CoreServiceImpl implements CoreService {public static Logger log = Logger.getLogger(CoreServiceImpl.class);@Overridepublic String processRequest(HttpServletRequest request) {String respMessage = null;try {// 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(Constant.RESP_MESSAGE_TYPE_TEXT);textMessage.setFuncFlag(0);// 文本消息if (msgType.equals(Constant.REQ_MESSAGE_TYPE_TEXT)) {// 接收用户发送的文本消息内容String content = requestMap.get("Content");// 创建图文消息NewsMessage newsMessage = new NewsMessage();newsMessage.setToUserName(fromUserName);newsMessage.setFromUserName(toUserName);newsMessage.setCreateTime(new Date().getTime());newsMessage.setMsgType(Constant.RESP_MESSAGE_TYPE_NEWS);newsMessage.setFuncFlag(0);List<Article> articleList = new ArrayList<Article>();// 单图文消息if ("1".equals(content)) {Article article = new Article();article.setTitle("我是一条单图文消息");article.setDescription("我是描述信息,哈哈哈哈哈哈哈。。。");article.setPicUrl("http://www.iteye.com/upload/logo/user/603624/2dc5ec35-073c-35e7-9b88-274d6b39d560.jpg");article.setUrl("http://tuposky.iteye.com");articleList.add(article);// 设置图文消息个数newsMessage.setArticleCount(articleList.size());// 设置图文消息包含的图文集合newsMessage.setArticles(articleList);// 将图文消息对象转换成xml字符串respMessage = MessageUtil.newsMessageToXml(newsMessage);}// 多图文消息else if ("3".equals(content)) {Article article1 = new Article();article1.setTitle("我是一条多图文消息");article1.setDescription("");article1.setPicUrl("http://www.isic.cn/viewResourcesAction//logo/20130913/2013091314543416032.jpg");article1.setUrl("http://tuposky.iteye.com/blog/2008583");Article article2 = new Article();article2.setTitle("微信公众平台开发教程Java版(二)接口配置 ");article2.setDescription("");article2.setPicUrl("http://www.isic.cn/viewResourcesAction//logo/20131021/2013102111243367254.jpg");article2.setUrl("http://tuposky.iteye.com/blog/2008655");Article article3 = new Article();article3.setTitle("微信公众平台开发教程Java版(三) 消息接收和发送");article3.setDescription("");article3.setPicUrl("http://www.isic.cn/viewResourcesAction//logo/20131021/2013102111291287031.jpg");article3.setUrl("http://tuposky.iteye.com/blog/2017429");articleList.add(article1);articleList.add(article2);articleList.add(article3);newsMessage.setArticleCount(articleList.size());newsMessage.setArticles(articleList);respMessage = MessageUtil.newsMessageToXml(newsMessage);} }} catch (Exception e) {e.printStackTrace();}return respMessage;}}

单个图文和多图文的处理方式其实是一样的

单图文的时候articleList 的size为1

多图文的时候为多个。

运行的效果截图如下:

用户发送1,单图文消息

用户发送3 多图文消息

Ps: 图文消息中的图片是可以引用外部资源的!

java微信开发教程相关推荐

  1. Java微信开发_00_资源汇总贴

    1.微信公众平台技术文档(https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432) 2.微信企业号开发接口文档(ht ...

  2. Java实例开发教程:SpringBoot开发案例

    最近在做邮件发送的服务,正常来说SpringBoot整合mail还是很方便的,然而来了新的需求:A请求使用邮箱C发送,B请求使用邮箱D发送,也就是说我们需要配置两套发送服务. 单实例 首先我们来看下单 ...

  3. java微信开发API解析(二)-获取消息和回复消息

    java微信开发API解析(二)-获取消息和回复消息 说明 * 本演示样例依据微信开发文档:http://mp.weixin.qq.com/wiki/home/index.html最新版(4/3/20 ...

  4. Java微信开发入门

    前言: 1.先简单介绍一下微信公众号的开发者模式和编辑模式,玩过微信公众号的同志都知道,在微信公众号后台功能栏里面可以编辑消息自动回复,关键字回复,自定义菜单等功能,这些都是在视图页面下编辑的,叫编辑 ...

  5. java微信开发-消息接收和自动回复

    0.前提条件 1.需要一个公众平台帐号(测试帐号也可以) 2.平台需要被人关注 1.导入jar commons-beanutils-1.8.0.jar commons-collections-3.1. ...

  6. java微信开发图文_java版微信公众号图文消息开发

    1 本篇主要介绍微信公众帐号开发中图文消息的使用 以及图文消息的几种表现形式 图文消息的主要参数说明 通过微信官方的消息接口指南,可以看到对图文消息的参数介绍,如下图所示: 从图中可以了解到: 1)图 ...

  7. 微信开发教程(4)——高级群发接口

    在这篇微信公众平台高级接口开发教程中我们将介绍如何使用接口实现微信公众平台群发功能. 本文分为以下四个部分 准备群发内容 选择群发对象 执行群发 接收群发结果 一.准备群发内容 群发内容可以是文本.图 ...

  8. java微信开发平台_Java微信公众平台开发(1) 接入微信公众平台

    前面几篇文章一直都在说微信公众平台的开发准备工作,那么从这篇开始我们就将正式的进入JAVA微信公众平台开发的整个流程,那么这篇我们开始聊聊如何将我们的服务端和微信公众平台对接! (一)接入流程解析 通 ...

  9. JAVA微信开发-新手接入指南

    相信很多人对微信开发已经不那么陌生,我也是从一个微信开发的菜鸟经过各种问题的折磨,然后去搜索引擎搜索各种文章阅读,但是基本都是零散的资料,没有一个统一.系统的阐述微信应用如何开发.作者结合自己的实际开 ...

最新文章

  1. 使用PyCharm定义QQ变量
  2. 【POJ - 1661】Help Jimmy(记忆化搜索,dp)
  3. Linux Shell脚本_较少Swap使用
  4. pandas 空字符串与na区别_python从安装到数据分析应用高手 Pandas处理文本数据(一)...
  5. java applet html_将图像从Java Applet传递到HTML
  6. python opencv3 —— findContours
  7. FFMPEG结构体分析:AVPacket
  8. ubuntu下C语言打开bmp图像文件并读取数据
  9. 软件企业CMMI认证需要什么条件?
  10. 学计算机理论课要记笔记吗,学生应该用笔记本电脑记笔记吗?
  11. 家用计算机按键不灵怎么修,电脑键盘两个ctrl键失灵怎么回事?ctrl键失灵的修复方法...
  12. win7各种插件的下载与使用
  13. 不同软件求解超导温度用的方程
  14. WIFI之一:WIFI常识 基站定位原理
  15. EL表达式中fn函数的强大功能,很简单,很好用,很强大
  16. android 进度条图标方形_android 进度条的样式
  17. 认真CS☀️增量时间—Time.deltaTime Time.fixedDeltaTime
  18. 微控制器在汽车驱动中的分析
  19. 【扯】免费前端教程不会告诉你这些—知乎live摘录
  20. MATLAB-常微分方程求解

热门文章

  1. Redis command timed out 两种异常情况
  2. Painter not active
  3. Vert.x入坑须知(3)
  4. c# 发送outlook邮件,设置html样式
  5. python实现神奇魔方阵(纵横图)
  6. Scripts的下载及安装(手动部署)
  7. 封神台之萌新也能找CMS漏洞整理记录
  8. SRV记录生成的完整教程
  9. vs中readfile的作用_VC 中 ReadFile 和 WriteFile 函数读写串口超时机制
  10. 【模电—低频学习笔记(一)】信号的频谱