1.前言
微信公众平台服务器配置通过后,就能进行下面的开发啦
首先可以查看官方的说明文档:https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html
普通消息的类型分为7种:
- 文本消息
- 图片消息
- 语音消息
- 视频消息
- 小视频消息
- 地理位置消息
- 链接消息
本文使用的是文本消息与图片消息
2.图文消息的自动回复
2.1 文本消息
文本消息的XML结构是:
1 2 3 4 5 6 7 8
| <xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[this is a test]]></Content> <MsgId>1234567890123456</MsgId> </xml>
|
参数包含:
定义一个BaseMessage,消息基类,封装通用属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
@Data public class BaseMessage { private String ToUserName; private String FromUserName; private String CreateTime; private String MsgType; private long MsgId;
private int FuncFlag; }
|
接下来定义文本消息属性TextMessage:
1 2 3 4 5 6 7 8
|
@Data public class TextMessage extends BaseMessage{ private String Content; }
|
2.2 图片消息
图片消息的XML结构是:
1 2 3 4 5 6 7 8 9
| <xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[image]]></MsgType> <PicUrl><![CDATA[this is a url]]></PicUrl> <MediaId><![CDATA[media_id]]></MediaId> <MsgId>1234567890123456</MsgId> </xml>
|
参数包含:
1 2 3
| @Data public class ImageMessage extends BaseMessage{ }
|
2.3 图文消息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Data public class Article {
private String Description;
private String PicUrl;
private String Title;
private String Url; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
@Setter @Getter public class NewsMessage extends BaseMessage{
private Integer ArticleCount;
private List<Article> Articles; }
|
3.功能实现
3.1 工具类MessageUtil
- 解析微信发来的请求(xml)
- 将响应消息的Java对象转换成xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
| public class MessageUtil {
public static final String RESP_MESSAGE_TYPE_TEXT = "text";
public static final String RESP_MESSAGE_TYPE_MUSIC = "music";
public static final String RESP_MESSAGE_TYPE_NEWS = "news";
public static final String REQ_MESSAGE_TYPE_TEXT = "text";
public static final String REQ_MESSAGE_TYPE_IMAGE = "image";
public static final String REQ_MESSAGE_TYPE_LINK = "link";
public static final String REQ_MESSAGE_TYPE_LOCATION = "location";
public static final String REQ_MESSAGE_TYPE_VOICE = "voice";
public static final String REQ_MESSAGE_TYPE_EVENT = "event";
public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
public static final String EVENT_TYPE_CLICK = "CLICK";
public static Map<String, String> xmlToMap(HttpServletRequest request) throws IOException { Map<String, String> map = new HashMap<String, String>(); SAXReader reader = new SAXReader();
InputStream ins = null; try { ins = request.getInputStream(); } catch (IOException e1) { e1.printStackTrace(); } Document doc = null; try { doc = reader.read(ins); Element root = doc.getRootElement();
List<Element> list = root.elements();
for (Element e : list) { map.put(e.getName(), e.getText()); }
return map; } catch (DocumentException e1) { e1.printStackTrace(); }finally{ ins.close(); } return null; }
public static Map<String, String> parseXml(HttpServletRequest request) throws Exception { Map<String, String> map = new HashMap<String, String>(); InputStream inputStream = request.getInputStream(); SAXReader reader = new SAXReader(); Document document = reader.read(inputStream); 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; }
public static String textMessageToXml(TextMessage textMessage){
xstream.alias("xml", textMessage.getClass()); return xstream.toXML(textMessage); }
public static String newsMessageToXml(NewsMessage newsMessage) { xstream.alias("xml", newsMessage.getClass()); xstream.alias("item", new Article().getClass()); return xstream.toXML(newsMessage); }
public static String imageMessageToXml(ImageMessage imageMessage) { xstream.alias("xml", imageMessage.getClass()); return xstream.toXML(imageMessage); }
private static XStream xstream = new XStream(new XppDriver() { public HierarchicalStreamWriter createWriter(Writer out) { return new PrettyPrintWriter(out) { boolean cdata = true;
@SuppressWarnings("rawtypes") public void startNode(String name, Class clazz) { super.startNode(name, clazz); }
protected void writeText(QuickWriter writer, String text) { if (cdata) { writer.write("<![CDATA["); writer.write(text); writer.write("]]>"); } else { writer.write(text); } } }; } }); }
|
3.2 实现
当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应(现支持回复文本
、图片
、图文
、语音
、视频
、音乐
)。
上一篇文章,已经创建了IndexController ,里面的GET方法用来验证token,下面直接加一个POST方法,用于进行消息管理。消息接收POST
和微信认证GET
是同一个接口(开发者填写的URL)
Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @PostMapping public void msgProcess(HttpServletRequest request, HttpServletResponse response) throws Exception { try { request.setCharacterEncoding("UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } response.setCharacterEncoding("UTF-8"); String respMessage = msgService.processRequest(request); PrintWriter out = null; try { out = response.getWriter(); out.print(respMessage); } catch (IOException e) { e.printStackTrace(); } finally { out.close(); out = null; } }
|
Service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| @Service public class MsgService { private static final Logger LOGGER = LoggerFactory.getLogger(MsgService.class);
public String processRequest(HttpServletRequest request) { String respMessage = null; System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); try { Map<String, String> requestMap = MessageUtil.xmlToMap(request); String fromUserName = requestMap.get("FromUserName"); String toUserName = requestMap.get("ToUserName"); String msgType = requestMap.get("MsgType"); String content = requestMap.get("Content"); LOGGER.info("FromUserName is:" + fromUserName + ", ToUserName is:" + toUserName + ", MsgType is:" + msgType); if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) { if (content.indexOf("天气")!=-1) {
NewsMessage newmsg = new NewsMessage(); newmsg.setToUserName(fromUserName); newmsg.setFromUserName(toUserName); newmsg.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); newmsg.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_NEWS); newmsg.setFuncFlag(0); List<Article> articleList = new ArrayList<>();
Article article = new Article(); article.setTitle("天气预报"); article.setDescription("点击了解未来天气详情..."); article.setPicUrl("https://lwy-image.oss-cn-beijing.aliyuncs.com/ep.png"); article.setUrl("https://widget-page.heweather.net/h5/index.html?bg=1&md=0123456&lc=auto&key=f1688db9422246fc969a6ba559075097"); articleList.add(article); newmsg.setArticleCount(articleList.size()); newmsg.setArticles(articleList); respMessage = MessageUtil.newsMessageToXml(newmsg); } } } catch (Exception e) { LOGGER.error("error......"); } return respMessage; } }
|
测试
源码参考 https://github.com/zhouminpz/wechatPublicAccount-