开发环境的准备
配置jdk和tomcat
集成开发环境idea或eclipse
下载安装外网映射花生壳或Sunny-Ngrok,软件不限
开发模式
开发模式的接入
登录微信公众平台官网后,在公众平台官网的开发-基本设置页面,勾选协议成为开发者,点击“修改配置”按钮,填写服务器地址(URL)、Token和EncodingAESKey,其中URL是开发者用来接收微信消息和事件的接口URL。Token可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)。EncodingAESKey由开发者手动填写或随机生成,将用作消息体加解密密钥。
开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示:
参数 |
描述 |
signature |
微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 |
timestamp |
时间戳 |
nonce |
随机数 |
echostr |
随机字符串 |
开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。
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
| package com.webchat.util; import java.security.MessageDigest; import java.util.Arrays; public class WxService { private static String token = "mywebchat"; public static boolean checkSignature(String signature, String timestamp, String nonce) { String[] strs = new String[]{token, timestamp, nonce}; Arrays.sort(strs);
String str = strs[0]+strs[1]+strs[2]; String mysig = sha1(str);
return mysig.equals(signature); }
private static String sha1(String str){ try { MessageDigest messageDigest = MessageDigest.getInstance("SHA1"); byte[] digest = messageDigest.digest(str.getBytes()); char[] chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; StringBuilder sb = new StringBuilder(); for (byte b : digest){ sb.append(chars[(b>>4)&15]); sb.append(chars[b&15]); } return sb.toString(); }catch (Exception e) { throw new RuntimeException(e); } } }
|
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
| package com.webchat.servlet;
import com.webchat.util.CheckUtil; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; @WebServlet("/mywebchat") public class WeixinServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String signature = req.getParameter("signature"); String timestamp = req.getParameter("timestamp"); String nonce = req.getParameter("nonce"); String echostr = req.getParameter("echostr");
if (CheckUtil.checkSignature(signature, timestamp, nonce)){ System.out.println("接入成功!"); PrintWriter out = resp.getWriter(); out.print(echostr); out.flush(); out.close(); }else { System.out.println("接入失败!"); } }
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
} }
|
接收消息
当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
- 在上方WeixinServlet的dopost方法中输入
1 2 3 4 5 6 7 8
| @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ request.setCharacterEncoding("utf8"); response.setCharacterEncoding("utf8"); Map<String,String> requestMap = WxService.parseRequest(request); System.out.println(requestMap); }
|
- 在上方的WxService里加入解析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
| public static Map<String,String> parseRequest(HttpServletRequest request) { Map<String, String> map = new HashMap<String, String>(); SAXReader reader = new SAXReader(); try { InputStream inputStream = request.getInputStream(); Document document = reader.read(inputStream); Element root = document.getRootElement(); List<Element> elementList = root.elements(); for (Element e : elementList) { map.put(e.getName(), e.getStringValue()); } inputStream.close(); return map; } catch (Exception e) { e.printStackTrace(); } return null; }
|
消息的封装
- 创建com.webchat.entity.message目录,并在目录下创建BaseMessage,class
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
| package com.webchat.entity.message; import com.thoughtworks.xstream.annotations.XStreamAlias; import java.util.Map;
@XStreamAlias("xml") public class BaseMessage { @XStreamAlias("ToUserName") private String toUserName;
@XStreamAlias("FromUserName") private String fromUserName;
@XStreamAlias("CreateTime") private String createTime;
@XStreamAlias("MsgType") private String msgType;
public BaseMessage(Map<String,String> requestMap) { this.toUserName = requestMap.get("FromUserName"); this.fromUserName = requestMap.get("ToUserName"); this.createTime = System.currentTimeMillis()/1000+""; }
public String getToUserName() { return toUserName; }
public void setToUserName(String toUserName) { this.toUserName = toUserName; }
public String getFromUserName() { return fromUserName; }
public void setFromUserName(String fromUserName) { this.fromUserName = fromUserName; }
public String getCreateTime() { return createTime; }
public void setCreateTime(String createTime) { this.createTime = createTime; }
public String getMsgType() { return msgType; }
public void setMsgType(String msgType) { this.msgType = msgType; }
@Override public String toString() { return "BaseMessage{" + "toUserName='" + toUserName + '\'' + ", fromUserName='" + fromUserName + '\'' + ", createTime='" + createTime + '\'' + ", msgType='" + msgType + '\'' + '}'; } }
|
- 在com.webchat.entity.message目录下创建继承BaseMessage的ImageMessage类
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
| package com.webchat.entity.message; import com.thoughtworks.xstream.annotations.XStreamAlias; import java.util.Map;
@XStreamAlias("xml") public class ImageMessage extends BaseMessage { @XStreamAlias("MediaId") private String mediaId;
public String getMediaId() { return mediaId; }
public void setMediaId(String mediaId) { this.mediaId = mediaId; }
public ImageMessage(Map<String, String> requestMap,String mediaId) { super(requestMap); this.setMsgType("image"); this.mediaId = mediaId; }
@Override public String toString() { return "ImageMessage{" + "mediaId=" + mediaId +",toUserName=" +getToUserName() +",fromUserName="+getFromUserName()+",createTime="+getCreateTime() +"}"; } }
|
- 在com.webchat.entity.message目录下创建继承BaseMessage的TextMessage类
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
| package com.webchat.entity.message; import com.thoughtworks.xstream.annotations.XStreamAlias; import java.util.Map;
@XStreamAlias("xml") public class TextMessage extends BaseMessage { @XStreamAlias("Content") private String content;
public String getContent() { return content; }
public void setContent(String content) { this.content = content; }
public TextMessage(Map<String,String> requestMap,String content) { super(requestMap); this.setMsgType("text"); this.content = content; }
@Override public String toString() { return "TextMessage{" + "content=" + content +",toUserName=" +getToUserName() +",fromUserName="+getFromUserName()+",createTime="+getCreateTime() +"}"; } }
|
- 在com.webchat.entity.message目录下创建继承BaseMessage的VideoMessage类
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
| package com.webchat.entity.message; import com.thoughtworks.xstream.annotations.XStreamAlias; import java.util.Map; @XStreamAlias("xml") public class VideoMessage extends BaseMessage { @XStreamAlias("MediaId") private String mediaId;
@XStreamAlias("Title") private String title;
@XStreamAlias("Description") private String description;
public String getMediaId() { return mediaId; }
public void setMediaId(String mediaId) { this.mediaId = mediaId; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public VideoMessage(Map<String, String> requestMap, String mediaId, String title, String description) { super(requestMap); this.setMsgType("video"); this.mediaId = mediaId; this.title = title; this.description = description; }
@Override public String toString() { return "VideoMessage{" + "mediaId=" + mediaId +",title="+getTitle() +",description="+getDescription()+",toUserName=" +getToUserName() +",fromUserName="+getFromUserName()+",createTime="+getCreateTime() +"}"; } }
|
- 在com.webchat.entity.message目录下创建继承BaseMessage的VoiceMessage类
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
| package com.webchat.entity.message; import com.thoughtworks.xstream.annotations.XStreamAlias; import java.util.Map; @XStreamAlias("xml") public class VoiceMessage extends BaseMessage { @XStreamAlias("MediaId") private String mediaId;
public String getMediaId() { return mediaId; }
public void setMediaId(String mediaId) { this.mediaId = mediaId; }
public VoiceMessage(Map<String, String> requestMap, String mediaId) { super(requestMap); this.setMsgType("voice"); this.mediaId = mediaId; }
@Override public String toString() { return "VoiceMessage{" + "mediaId=" + mediaId +",toUserName=" +getToUserName() +",fromUserName="+getFromUserName()+",createTime="+getCreateTime() +"}"; } }
|
- 在com.webchat.entity.message目录下创建继承BaseMessage的MusicMessage类,还要建music的实体类
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
| package com.webchat.entity.message; import com.thoughtworks.xstream.annotations.XStreamAlias; import java.util.Map; @XStreamAlias("xml") public class MusicMessage extends BaseMessage { @XStreamAlias("Music") private Music music;
public Music getMusic() { return music; }
public void setMusic(Music music) { this.music = music; }
public MusicMessage(Map<String, String> requestMap, Music music) { super(requestMap); this.setMsgType("music"); this.music = music; }
@Override public String toString() { return "MusicMessage{" + "title=" + music.getTitle() +", description=" + music.getDescription() +", musicURL=" + music.getMusicURL()+", hQMusicUrl=" + music.gethQMusicUrl() +", thumbMediaId=" + music.getThumbMediaId()+",toUserName=" +getToUserName() +",fromUserName="+getFromUserName()+",createTime="+getCreateTime() +'}'; } }
|
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
| package com.webchat.entity.message; import com.thoughtworks.xstream.annotations.XStreamAlias; @XStreamAlias("item") public class Music { private String title; private String description; private String musicURL; private String hQMusicUrl; private String thumbMediaId;
public Music(String title, String description, String musicURL, String hQMusicUrl, String thumbMediaId) { this.title = title; this.description = description; this.musicURL = musicURL; this.hQMusicUrl = hQMusicUrl; this.thumbMediaId = thumbMediaId; }
public String getThumbMediaId() { return thumbMediaId; }
public void setThumbMediaId(String thumbMediaId) { this.thumbMediaId = thumbMediaId; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getMusicURL() { return musicURL; }
public void setMusicURL(String musicURL) { this.musicURL = musicURL; }
public String gethQMusicUrl() { return hQMusicUrl; }
public void sethQMusicUrl(String hQMusicUrl) { this.hQMusicUrl = hQMusicUrl; }
@Override public String toString() { return "Music{" + "title='" + title + '\'' + ", description='" + description + '\'' + ", musicURL='" + musicURL + '\'' + ", hQMusicUrl='" + hQMusicUrl + '\'' + ", thumbMediaId='" + thumbMediaId + '\'' + '}'; } }
|
- 在com.webchat.entity.message目录下创建继承BaseMessage的NewsMessage类,还要建Article的实体类
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
| package com.webchat.entity.message; import com.thoughtworks.xstream.annotations.XStreamAlias; import java.util.ArrayList; import java.util.List; import java.util.Map; @XStreamAlias("xml") public class NewsMessage extends BaseMessage { @XStreamAlias("ArticleCount") private String articleCount; @XStreamAlias("Articles") private List<Article> articles = new ArrayList<>();
public String getArticleCount() { return articleCount; }
public void setArticleCount(String articleCount) { this.articleCount = articleCount; }
public List<Article> getArticles() { return articles; }
public void setArticles(List<Article> articles) { this.articles = articles; }
public NewsMessage(Map<String, String> requestMap, List<Article> articles) { super(requestMap); this.setMsgType("news"); this.articleCount = articles.size()+""; this.articles = articles; }
@Override public String toString() { return "NewsMessage{" + "articleCount='" + articleCount + '\'' + ", articles=" + articles + '}'; } }
|
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
| package com.webchat.entity.message; import com.thoughtworks.xstream.annotations.XStreamAlias; @XStreamAlias("item") public class Article { @XStreamAlias("Title") private String title;
@XStreamAlias("Description") private String description;
@XStreamAlias("PicUrl") private String picUrl;
@XStreamAlias("Url") private String url;
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getPicUrl() { return picUrl; }
public void setPicUrl(String picUrl) { this.picUrl = picUrl; }
public String getUrl() { return url; }
public void setUrl(String url) { this.url = url; }
public Article(String title, String description, String picUrl, String url) { this.title = title; this.description = description; this.picUrl = picUrl; this.url = url; }
@Override public String toString() { return "Article{" + "title='" + title + '\'' + ", description='" + description + '\'' + ", picUrl='" + picUrl + '\'' + ", url='" + url + '\'' + '}'; } }
|