Java微信公众号开发之工具类
- 访问令牌实体类
- 开发所需工具类
- 微信公众号接入及被动回复图文消息(controller)
- controller中使用到的实体类
- BaseMessageResp 基础信息响应对象
- TextMessageResp 文本消息响应
- ImageMessageResp 图片消息响应
- Image 图片
- VoiceMessageResp 语音消息响应
- Voice 语音
- VideoMessageResp 视频消息响应
- Video 视频
- MusicMessageResp 音乐消息响应
- Music 音乐
- ArticleMessageResp 图文消息响应
- Articles 图文消息列表
- Item 单个图文
访问令牌实体类
package com.tdzh.weixin.Entity;
/**
* className:AccessToken
* Package:com.tdzh.util
* Description:访问令牌实体类
*
* @date:2019/7/22 17:30
* @author:malin
*/
public class AccessToken {
//令牌字符串
private String accessToken;
//过期时间
private Long expiresIn;
private AccessToken() {
}
public AccessToken(String accessToken, String expiresIn) {
this.accessToken = accessToken;
//设置过期时间,创建后的一个小时59分钟内,防止在必要时刻,调用接口失败
this.expiresIn = System.currentTimeMillis() + Integer.parseInt(expiresIn) - 60;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public long getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(long expiresIn) {
this.expiresIn = expiresIn;
}
//判断当前访问令牌是否过期
public boolean isExpired(){
return System.currentTimeMillis() > expiresIn;
}
}
开发所需工具类
package com.tdzh.weixin.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tdzh.weixin.Entity.AccessToken;
import com.tdzh.weixin.Entity.resp.*;
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;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* className:WxUtil
* Package:com.tdzh.util
* Description:微信工具类,主要用来获取访问令牌,对实体类进行XMl转换
*
* @date:2019/7/22 15:23
* @author:malin
*/
@Component
public class WxUtil {
//token,用作生成签名,须于微信公众号端一致
@Value("${WeChat.token}")
private String token;
//第三方用户唯一凭证
@Value("${WeChat.appID}")
private String appID;
//第三方用户唯一凭证密钥,即appsecret
@Value("${WeChat.appsecret}")
private String appsecret;
//访问令牌实体
private AccessToken accessToken;
//对所有xml节点的转换都增加CDATA标记
private static XStream xstream = new XStream(new XppDriver() {
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out) {
// 对所有xml节点的转换都增加CDATA标记
boolean cdata = true;
@SuppressWarnings("unchecked")
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);
}
}
};
}
});
/**
* 微信接入校验,仅接入时使用
* @param signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
* @param timestamp 时间戳
* @param nonce 随机数
* @return
*/
public boolean WxAccess(String signature,String timestamp,String nonce){
//1)将token、timestamp、nonce三个参数进行字典序排序
String[] args = {token,timestamp,nonce};
Arrays.sort(args);
//2)将三个参数字符串拼接成一个字符串进行sha1加密
String str = args[0] + args[1] + args[2];
//加密字符串
String sha1 = getSha1(str);
//3)开发者获得加密后的字符串可与signature对比,true则标识该请求来源于微信
return sha1.equals(signature);
}
/**
* sha1 加密
* @param str 被加密字符串
* @return 加密字符串
*/
public String getSha1(String str){
try {
// 获取一个加密对象
MessageDigest md = MessageDigest.getInstance("sha1");
// 数据加密
byte[] digest = md.digest(str.getBytes());
char[] chars = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
//对字符串进行加密处理
StringBuffer sb = new StringBuffer();
for(byte b : digest){
sb.append(chars[b>>4 & 15]);
sb.append(chars[b & 15]);
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
/**
* 创建访问令牌,令牌过期时间为创建后的2小时
*/
public void createAccessToken(){
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET".replace("APPID",appID).replace("APPSECRET",appsecret);
//本人编写参考HttpClient工具类
Map<String, Object> stringObjectMap = HttpClientUtil.doGet(url);
//System.out.println(stringObjectMap.toString());
String content = (String) stringObjectMap.get("content");
JSONObject jsonObject = JSON.parseObject(content);
String access_token = (String) jsonObject.get("access_token");
String expires_in = jsonObject.get("expires_in").toString();
accessToken = new AccessToken(access_token,expires_in);
}
/**
* 获取访问令牌
* @return accessToken 访问令牌
*/
public String getAccessToken(){
//判断访问令牌是否存在或者过期,如若不存在或已过期,重新生成访问令牌
if (null == accessToken || accessToken.isExpired()) {
createAccessToken();
}
return accessToken.getAccessToken();
}
/**
* 解析微信发来的request请求
* @param request
* @return
*/
public Map<String,Object> parseXml(HttpServletRequest request){
Map<String,Object> resultMap = new HashMap<String,Object>();
// 从request中取得输入流
InputStream inputStream = null;
try {
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){
resultMap.put(e.getName(), e.getText());
}
} catch (IOException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
} finally {
// 释放资源
try {
if(null != inputStream){
inputStream.close();
inputStream = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return resultMap;
}
/**
* 响应文本消息对象转换成xml
* @param textMessageResp 文本消息对象
* @return
*/
public String textMessageToXml(TextMessageResp textMessageResp){
xstream.alias("xml",textMessageResp.getClass());
return xstream.toXML(textMessageResp);
}
/**
* 响应图片消息对象转换成xml
* @param imageMessageResp
* @return
*/
public String imageMessageToXml(ImageMessageResp imageMessageResp) {
xstream.alias("xml",imageMessageResp.getClass());
return xstream.toXML(imageMessageResp);
}
/**
* 响应语音消息对象转换成xml
* @param voiceMessageResp
* @return
*/
public String voiceMessageToXml(VoiceMessageResp voiceMessageResp) {
xstream.alias("xml",voiceMessageResp.getClass());
return xstream.toXML(voiceMessageResp);
}
/**
* 响应语音消息对象转换成xml
* @param videoMessageResp
* @return
*/
public String videoMessageToXml(VideoMessageResp videoMessageResp) {
xstream.alias("xml",videoMessageResp.getClass());
return xstream.toXML(videoMessageResp);
}
/**
* 响应音乐消息对象转换成xml
* @param musicMessageResp
* @return
*/
public String musicMessageToXml(MusicMessageResp musicMessageResp) {
xstream.alias("xml",musicMessageResp.getClass());
return xstream.toXML(musicMessageResp);
}
/**
* 响应图文消息对象转换成xml
* @param articleMessageResp
* @return
*/
public String articleMessageToXml(ArticleMessageResp articleMessageResp) {
xstream.alias("xml",articleMessageResp.getClass());
return xstream.toXML(articleMessageResp);
}
}
微信公众号接入及被动回复图文消息(controller)
package com.tdzh.weixin.controller;
import com.tdzh.weixin.Entity.*;
import com.tdzh.weixin.Entity.resp.*;
import com.tdzh.weixin.util.WxUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* className:CheckController
* Package:com.tdzh.weixin.controller
* Description:1、微信接入校验 2、微信相关信息被动回复
*
* @date:2019/7/26 17:03
* @author:malin
*/
@RestController
@RequestMapping("/check")
public class CheckController {
@Autowired
private WxUtil wxUtil;
/**
* 微信接入校验
* @param request
*/
@GetMapping("/weChat")
public String checkGetRequestFromWeChat(HttpServletRequest request){
String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String echostr = request.getParameter("echostr");
System.out.println("校验中...");
boolean flag = wxUtil.WxAccess(signature, timestamp, nonce);
if(flag){
System.out.println("校验成功...");
return echostr;
}else{
System.out.println("校验失败...");
return null;
}
}
/**
* 被动回复消息事件处理
* @param request
*/
@PostMapping("/weChat")
public String weChatMessageReceive(HttpServletRequest request){
//解析微信端发送来的xml包,并获得相应的map
Map<String, Object> stringObjectMap = wxUtil.parseXml(request);
//输出,后期删除
//System.out.println(stringObjectMap);
//返回xml数据包
String returnMessage = null;
//基础数据准备
String msgType = (String) stringObjectMap.get("MsgType");
switch (msgType){
case "text" :
TextMessageResp textMessageResp = new TextMessageResp(stringObjectMap,"hello ,boy");
returnMessage = wxUtil.textMessageToXml(textMessageResp);
break;
case "image" :
//此处的mediaId为通过素材管理中的接口上传多媒体文件,得到的id。
Image image = new Image(mediaId);
ImageMessageResp imageMessageResp = new ImageMessageResp(stringObjectMap,image);
returnMessage = wxUtil.imageMessageToXml(imageMessageResp);
break;
case "voice" :
//此处的mediaId为通过素材管理中的接口上传多媒体文件,得到的id。
Voice voice = new Voice(mediaId);
VoiceMessageResp voiceMessageResp = new VoiceMessageResp(stringObjectMap, voice);
returnMessage = wxUtil.voiceMessageToXml(voiceMessageResp);
break;
case "video" :
//此处的mediaId为通过素材管理中的接口上传多媒体文件,得到的id。
Video video = new Video(mediaId,"下雨了","雨下的很大");
VideoMessageResp videoMessageResp = new VideoMessageResp(stringObjectMap, video);
returnMessage = wxUtil.videoMessageToXml(videoMessageResp);
break;
case "music" :
//此处本人未测试成功,但返回格式正确
Music music = new Music("安河桥","这是一首很棒的民谣","https://music.163.com/outchain/player?type=2&id=566521546&auto=1&height=66","https://music.163.com/outchain/player?type=2&id=566521546&auto=1&height=66","hkbuYI2WOLNLBCwtsOO3KlP6Vaxcc8OMQ1H4pfPzsIk11SgL5wozM72kfkCLFMlw");
MusicMessageResp musicMessageResp = new MusicMessageResp(stringObjectMap,music);
returnMessage = wxUtil.musicMessageToXml(musicMessageResp);
break;
case "news":
Item item = new Item("文章1","这是一篇测试文章","http://pic25.nipic.com/20121112/9252150_150552938000_2.jpg","https://www.baidu.com/");
Articles articles = new Articles(item);
ArticleMessageResp articleMessageResp = new ArticleMessageResp(stringObjectMap,1,articles);
returnMessage = wxUtil.articleMessageToXml(articleMessageResp);
break;
}
//System.out.println(returnMessage);
return returnMessage;
}
}
controller中使用到的实体类
BaseMessageResp 基础信息响应对象
package com.tdzh.weixin.Entity.resp;
import java.util.Date;
import java.util.Map;
/**
* className:BaseMessageResp
* Package:com.tdzh.weixin.Entity.resp
* Description:基础信息返回对象
*
* @date:2019/7/29 8:26
* @author:malin
*/
public class BaseMessageResp {
//接收方帐号(收到的OpenID)
private String ToUserName;
//开发者微信号
private String FromUserName;
//消息创建时间 (整型)
private Long CreateTime;
//消息类型,文本为text,图片为img,语音为voice,视频为video,小视频为shortvideo,地理位置为location,链接为link
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;
}
public BaseMessageResp(Map<String,Object> requestMap){
this.MsgType = (String) requestMap.get("MsgType");
this.FromUserName = (String) requestMap.get("ToUserName");
this.ToUserName = (String) requestMap.get("FromUserName");
this.CreateTime = new Date().getTime();
}
}
TextMessageResp 文本消息响应
package com.tdzh.weixin.Entity.resp;
import java.util.Map;
/**
* className:TextMessageResp
* Package:com.tdzh.weixin.Entity.resp
* Description:文字信息返回对象
*
* @date:2019/7/31 11:13
* @author:malin
*/
public class TextMessageResp extends BaseMessageResp{
//文本消息内容
private String Content;
public String getContent() {
return Content;
}
public void setContent(String content) {
Content = content;
}
public TextMessageResp(Map<String, Object> requestMap, String content) {
super(requestMap);
this.Content = content;
}
}
ImageMessageResp 图片消息响应
package com.tdzh.weixin.Entity.resp;
import com.tdzh.weixin.Entity.Image;
import java.util.Map;
/**
* className:ImageMessageResp
* Package:com.tdzh.weixin.Entity.resp
* Description:图片信息返回对象
*
* @date:2019/7/29 8:28
* @author:malin
*/
public class ImageMessageResp extends BaseMessageResp {
private Image Image;
public Image getImage() {
return Image;
}
public void setImage(Image image) {
this.Image = image;
}
public ImageMessageResp(Map<String, Object> requestMap, Image image) {
super(requestMap);
this.Image = image;
}
}
Image 图片
package com.tdzh.weixin.Entity;
/**
* className:Image
* Package:com.tdzh.weixin.Entity
* Description:图片实体类
*
* @date:2019/7/29 8:29
* @author:malin
*/
public class Image {
//通过素材管理中的接口上传多媒体文件,得到的id。
private String MediaId;
public String getMediaId() {
return MediaId;
}
public void setMediaId(String mediaId) {
MediaId = mediaId;
}
public Image(String mediaId) {
MediaId = mediaId;
}
}
VoiceMessageResp 语音消息响应
package com.tdzh.weixin.Entity.resp;
import com.tdzh.weixin.Entity.Voice;
import java.util.Map;
/**
* className:VoiceMessageResp
* Package:com.tdzh.weixin.Entity.resp
* Description:语音信息返回对象
*
* @date:2019/7/29 10:11
* @author:malin
*/
public class VoiceMessageResp extends BaseMessageResp{
private Voice Voice;
public VoiceMessageResp(Map<String, Object> requestMap, Voice voice) {
super(requestMap);
this.Voice = voice;
}
public com.tdzh.weixin.Entity.Voice getVoice() {
return Voice;
}
public void setVoice(com.tdzh.weixin.Entity.Voice voice) {
Voice = voice;
}
}
Voice 语音
package com.tdzh.weixin.Entity;
/**
* className:Voice
* Package:com.tdzh.weixin.Entity
* Description:语音实体类
*
* @date:2019/7/27 18:07
* @author:malin
*/
public class Voice {
//通过素材管理中的接口上传多媒体文件,得到的id
private String MediaId;
public String getMediaId() {
return MediaId;
}
public void setMediaId(String mediaId) {
MediaId = mediaId;
}
public Voice(String mediaId) {
MediaId = mediaId;
}
}
VideoMessageResp 视频消息响应
package com.tdzh.weixin.Entity.resp;
import com.tdzh.weixin.Entity.Video;
import java.util.Map;
/**
* className:VideoMessageResp
* Package:com.tdzh.weixin.Entity.resp
* Description:视频信息返回对象
*
* @date:2019/7/29 10:48
* @author:malin
*/
public class VideoMessageResp extends BaseMessageResp {
private Video Video;
public VideoMessageResp(Map<String, Object> requestMap, Video Video) {
super(requestMap);
this.Video = Video;
}
public Video getVideo() {
return Video;
}
public void setVideo(Video Video) {
this.Video = Video;
}
}
Video 视频
package com.tdzh.weixin.Entity;
/**
* className:Video
* Package:com.tdzh.weixin.Entity
* Description:视频实体类
*
* @date:2019/7/29 10:45
* @author:malin
*/
public class Video {
private String MediaId;
private String Title;
private String Description;
public Video(){
}
public Video(String mediaId, String title, String description) {
this.MediaId = mediaId;
this.Title = title;
this.Description = description;
}
public String getMediaId() {
return MediaId;
}
public void setMediaId(String mediaId) {
MediaId = mediaId;
}
public String getTitle() {
return Title;
}
public void setTitle(String title) {
Title = title;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
}
MusicMessageResp 音乐消息响应
package com.tdzh.weixin.Entity.resp;
import com.tdzh.weixin.Entity.Music;
import java.util.Map;
/**
* className:MusicMessageResp
* Package:com.tdzh.weixin.Entity.resp
* Description:音乐信息返回对象
*
* @date:2019/7/29 11:13
* @author:malin
*/
public class MusicMessageResp extends BaseMessageResp{
private Music Music;
public MusicMessageResp(Map<String, Object> requestMap,Music Music) {
super(requestMap);
this.Music = Music;
}
public Music getMusic() {
return Music;
}
public void setMusic(Music music) {
this.Music = music;
}
}
Music 音乐
package com.tdzh.weixin.Entity;
/**
* className:Music
* Package:com.tdzh.weixin.Entity
* Description:音乐实体类
*
* @date:2019/7/29 10:57
* @author:malin
*/
public class Music {
//音乐标题
private String Title;
//音乐描述
private String Description;
//音乐链接
private String MusicURL;
//高质量音乐链接,WIFI环境优先使用该链接播放音乐
private String HQMusicUrl;
//缩略图的媒体id,通过素材管理中的接口上传多媒体文件,得到的id
private String ThumbMediaId;
public Music(String title, String description, String musicURL, String HQMusicUrl, String thumbMediaId) {
Title = title;
Description = description;
MusicURL = musicURL;
this.HQMusicUrl = HQMusicUrl;
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;
}
public String getThumbMediaId() {
return ThumbMediaId;
}
public void setThumbMediaId(String thumbMediaId) {
this.ThumbMediaId = thumbMediaId;
}
}
ArticleMessageResp 图文消息响应
package com.tdzh.weixin.Entity.resp;
import com.tdzh.weixin.Entity.Articles;
import java.util.Map;
/**
* className:ArticleMessageResp
* Package:com.tdzh.weixin.Entity.resp
* Description:图文信息返回对象
*
* @date:2019/7/29 11:35
* @author:malin
*/
public class ArticleMessageResp extends BaseMessageResp{
private Integer ArticleCount;
private Articles Articles;
public ArticleMessageResp(Map<String, Object> requestMap, Integer ArticleCount , Articles Articles) {
super(requestMap);
this.ArticleCount = ArticleCount;
this.Articles = Articles;
}
public Integer getArticleCount() {
return ArticleCount;
}
public void setArticleCount(Integer articleCount) {
ArticleCount = articleCount;
}
public com.tdzh.weixin.Entity.Articles getArticles() {
return Articles;
}
public void setArticles(com.tdzh.weixin.Entity.Articles articles) {
Articles = articles;
}
}
Articles 图文消息列表
package com.tdzh.weixin.Entity;
/**
* className:Articles
* Package:com.tdzh.weixin.Entity
* Description:文章实体类
*
* @date:2019/7/29 11:29
* @author:malin
*/
public class Articles {
private Item item;
public Articles(Item item) {
this.item = item;
}
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
}
Item 单个图文
package com.tdzh.weixin.Entity;
/**
* className:Item
* Package:com.tdzh.weixin.Entity
* Description:文章子实体类
*
* @date:2019/7/29 11:30
* @author:malin
*/
public class Item {
private String Title;
private String Description;
private String PicUrl;
private String Url;
public Item(String title, String description, String picUrl, String url) {
this.Title = title;
this.Description = description;
this.PicUrl = picUrl;
this.Url = 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;
}
}