1、项目目录:
二、、pojo相关实体类
1>、图文消息类
package com.winxin.pojo;
/**
* 图文消息
* @author cdj
* @date 2018年8月3日 上午8:45:56
*/
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;
}
}
2>、消息体基础类
package com.winxin.pojo;
/**
* 消息体基础类
* @author cdj
*/
public class BaseMessage {
private String ToUserName;
private String FromUserName;
private long CreateTime;
private String MsgType;
private long MsgId;
private int FuncFlag;
public int getFuncFlag() {
return FuncFlag;
}
public void setFuncFlag(int funcFlag) {
FuncFlag = 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 long getMsgId() {
return MsgId;
}
public void setMsgId(long msgId) {
MsgId = msgId;
}
}
3>、音乐消息类
package com.winxin.pojo;
/**
* 音乐消息
* @author cdj
* @date 2018年8月3日 上午8:46:59
*/
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;
}
}
4>、语音消息类
package com.winxin.pojo;
/**
* 语音消息
*
* @author cdj
* @date 2018年8月3日 上午8:29:49
*/
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;
}
}
5>、文本消息类
package com.winxin.pojo;
/**
* 文本消息类
* @author cdj
*/
public class TextMessage extends BaseMessage{
private String Content;
public String getContent() {
return Content;
}
public void setContent(String content) {
Content = content;
}
}
6>、 多图文消息
package com.winxin.pojo;
import java.util.List;
/**
* 多图文消息,
* 单图文的时候 Articles 只放一个就行了
* @author cdj
* @date 2018年8月3日 上午8:45:22
*/
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;
}
}
7>、音乐消息
package com.winxin.pojo;
/**
* 音乐消息
* @author cdj
* @date 2018年8月3日 上午8:46:35
*/
public class MusicMessage extends BaseMessage {
/**
* 音乐
*/
private Music Music;
public Music getMusic() {
return Music;
}
public void setMusic(Music music) {
Music = music;
}
}
8>、位置消息
package com.winxin.pojo;
/**
* 位置消息
* @author cdj
* @date 2018年8月3日 上午8:30:35
*/
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;
}
}
9>、链接消息接受
package com.winxin.pojo;
/**
* 链接消息接受
* @author cdj
* @date 2018年8月3日 上午8:29:06
*/
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;
}
}
10>、 图片消息事件接受
package com.winxin.pojo;
/**
* 图片消息事件接受
* @author cdj
* @date 2018年8月3日 上午8:28:01
*/
public class ImageMessage extends BaseMessage {
private String picUrl;
public String getPicUrl() {
return picUrl;
}
public void setPicUrl(String picUrl) {
this.picUrl = picUrl;
}
}
11>、公众号 菜单
package com.winxin.pojo;
public class Menu {
private Button[] button;
public Button[] getButton() {
return button;
}
public void setButton(Button[] button) {
this.button = button;
}
}
12>、菜单按钮
package com.winxin.pojo;
public class Button {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
13>、一级菜单按钮
package com.winxin.pojo;
public class CommonButton extends Button {
private String type;
private String key;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
}
14>、不同级菜单按钮
package com.winxin.pojo;
public class ComplexButton extends Button {
private Button[] sub_button;
public Button[] getSub_button() {
return sub_button;
}
public void setSub_button(Button[] sub_button) {
this.sub_button = sub_button;
}
}
三、工具类
1、通用工具类
package com.winxin.util;
import com.winxin.pojo.Token;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import sun.net.www.protocol.http.HttpURLConnection;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.rmi.ConnectException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 描述: 通用工具类
*
* @description
* @time 2019/3/18
*/
public class CommonUtil {
public static volatile Map<String, Token> tokenMap = new ConcurrentHashMap<String, Token>();
//微信通用接口凭证
private static Token token = null;
/**
* 发送https请求
*
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
*/
public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
JSONObject jsonObject = null;
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = {new MyX509TrustManager()};
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(ssf);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
// 当outputStr不为null时向输出流写数据
if (null != outputStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = conn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
// 释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
conn.disconnect();
jsonObject = JSONObject.fromObject(buffer.toString());
} catch (ConnectException ce) {
System.out.println("连接超时:" + ce);
} catch (Exception e) {
System.out.println("https请求异常:" + e);
}
return jsonObject;
}
/**
* 2.发起http请求获取返回结果
*
* @param requestUrl 请求地址
* @return
*/
public static JSONObject httpRequest(String requestUrl) {
JSONObject jsonObject = null;
StringBuffer buffer = new StringBuffer();
try {
URL url = new URL(null, requestUrl, new sun.net.www.protocol.https.Handler());
HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();
httpUrlConn.setDoOutput(false);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
httpUrlConn.setRequestMethod("GET");
httpUrlConn.connect();
// 将返回的输入流转换成字符串
InputStream inputStream = httpUrlConn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
jsonObject = JSONObject.fromObject(buffer.toString());
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
inputStream = null;
httpUrlConn.disconnect();
} catch (Exception e) {
System.out.println(e);
}
return jsonObject;
}
/**
* 获取接口访问凭证
*
* @return
*/
public static Token getToken() {
//如果tokenMap已经有缓存token,直接返回,不用请求微信接口
String key = Constant.APP_ID + "_" + Constant.APP_SECRET;
String requestUrl = Constant.GET_TOKEN_URL.replace("{APPID}", Constant.APP_ID).replace("{APPSECRET}", Constant.APP_SECRET);
// 发起GET请求获取凭证
JSONObject jsonObject = httpsRequest(requestUrl, "GET", null);
if (null != jsonObject) {
try {
token = new Token();
token.setAccessToken(jsonObject.getString("access_token"));
token.setExpiresIn(jsonObject.getInt("expires_in"));
System.out.println("获取token成功,缓存进tokenMap中 accessToken = " + token.getAccessToken());
tokenMap.put(key, token);
} catch (JSONException e) {
token = null;
// 获取token失败
System.out.println("获取token失败 errcode:" + jsonObject.getInt("errcode") + " errmsg:" + jsonObject.getString("errmsg"));
}
}
return token;
}
}
2、微信公众号接口相关的常量
package com.winxin.util;
/**
* @className:Constant
* @description: TODO
* @date: 2019-03-18 18:46
*/
public class Constant {
public final static String APP_ID = "你的APPID";
public final static String APP_SECRET = "你的密钥";
/**
* 凭证获取(GET)
*/
public final static String GET_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={APPID}&secret={APPSECRET}";
/**
* 自定义菜单
*/
public final static String POST_CREATE_MENU = " https://api.weixin.qq.com/cgi-bin/menu/create?access_token={ACCESSTOKEN}";
/**
* 查询自定义菜单
*/
public final static String GET_SELECT_MENU = " https://api.weixin.qq.com/cgi-bin/menu/get?access_token={ACCESSTOKEN}";
/**
* 上传卡券logo
*/
public final static String POST_UPLOAD_LOGO = " https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token={ACCESSTOKEN}";
/**
* 创建门店
*/
public final static String POST_CREATE_DOOR = "http://api.weixin.qq.com/cgi-bin/poi/addpoi?access_token={ACCESSTOKEN}";
/**
* 创建会员卡
*/
public final static String POST_CREATE_CARD = "https://api.weixin.qq.com/card/create?access_token={ACCESSTOKEN}";
/**
* 创建二维码
*/
public final static String POST_CREATE_QRCARD = "https://api.weixin.qq.com/card/qrcode/create?access_token={ACCESSTOKEN}";
/**
* 查询code 接口
*/
public final static String POST_SELECT_CODE = "https://api.weixin.qq.com/card/code/get?access_token={ACCESSTOKEN}";
/**
* 创建白名单
*/
public final static String POST_CREATE_WHITE = "https://api.weixin.qq.com/card/testwhitelist/set?access_token={ACCESSTOKEN}";
/**
* 核销code 接口
*/
public final static String POST_EXAMMINE_CODE = "https://api.weixin.qq.com/card/code/consume?access_token={ACCESSTOKEN}";
/**
* 会员卡激活
*/
public final static String POST_ACTIVATE_CARD = "https://api.weixin.qq.com/card/membercard/activate?access_token={ACCESSTOKEN}";
}
3、微信时间常量
package com.winxin.util;
/**
* 微信事件常量
*
* @author cdj
* @date 2018年8月3日 下午1:17:08
*/
public class EventConstant {
/**
* 返回消息类型:文本
*/
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 RESP_MESSAGE_TYPE_Image = "image";
/**
* 返回消息类型:语音
*/
public static final String RESP_MESSAGE_TYPE_Voice = "voice";
/**
* 返回消息类型:视频
*/
public static final String RESP_MESSAGE_TYPE_Video = "video";
/**
* 请求消息类型:文本
*/
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_VIDEO = "video";
/**
* 请求消息类型:推送
*/
public static final String REQ_MESSAGE_TYPE_EVENT = "event";
/**
* 事件类型:subscribe(订阅)
*/
public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
/**
* 事件类型:unsubscribe(取消订阅)
*/
public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
/**
* 事件类型:CLICK(自定义菜单点击事件)
*/
public static final String EVENT_TYPE_CLICK = "CLICK";
/**
* 事件类型:VIEW(自定义菜单URl视图)
*/
public static final String EVENT_TYPE_VIEW = "VIEW";
/**
* 事件类型:LOCATION(上报地理位置事件)
*/
public static final String EVENT_TYPE_LOCATION = "LOCATION";
/**
* 事件类型:LOCATION(上报地理位置事件)
*/
public static final String EVENT_TYPE_SCAN = "SCAN";
}
4、文本信息
package com.winxin.util;
public class MessageText {
private String Content;
private String CreateTime;
private String FromUserName;
private String MsgID;
private String MsgType;
private String ToUserName;
public MessageText() {
// TODO Auto-generated constructor stub
}
public MessageText(String toUserName, String fromUserName,
String createTime, String msgType, String content, String msgID) {
ToUserName = toUserName;
FromUserName = fromUserName;
CreateTime = createTime;
MsgType = msgType;
Content = content;
MsgID = msgID;
}
public String getContent() {
return Content;
}
public void setContent(String content) {
Content = content;
}
public String getCreateTime() {
return CreateTime;
}
public void setCreateTime(String createTime) {
CreateTime = createTime;
}
public String getFromUserName() {
return FromUserName;
}
public void setFromUserName(String fromUserName) {
FromUserName = fromUserName;
}
public String getMsgID() {
return MsgID;
}
public void setMsgID(String msgID) {
MsgID = msgID;
}
public String getMsgType() {
return MsgType;
}
public void setMsgType(String msgType) {
MsgType = msgType;
}
public String getToUserName() {
return ToUserName;
}
public void setToUserName(String toUserName) {
ToUserName = toUserName;
}
}
5、微信时间消息处理
package com.winxin.util;
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 com.winxin.pojo.Article;
import com.winxin.pojo.MusicMessage;
import com.winxin.pojo.NewsMessage;
import com.winxin.pojo.TextMessage;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 微信事件消息处理
* @author cdj
* @date 2018年8月3日 上午9:26:27
*/
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>();
// 读取输入流
SAXReader reader = new SAXReader();
// 从request中取得输入流
InputStream inputStream = request.getInputStream();
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;
@Override
protected void writeText(QuickWriter writer, String text) {
if (cdata) {
writer.write("<![CDATA[");
writer.write(text);
writer.write("]]>");
} else {
writer.write(text);
}
}
};
}
});
}
6、消息类型
package com.winxin.util;
public enum MsgType {
text("文本"),image("图片"),location("地理位置"),link("连接"),event("事件"),news("图文信息") ;
private String value;
public String getValue() {
return value;
}
private MsgType(String value) {
this.value = value;
}
}
7、信任管理器
package com.winxin.util;
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* 描述: 信任管理器
*
* @description
* @time 2019/3/18
*/
public class MyX509TrustManager implements X509TrustManager {
/**
* 检查客户端证书
*
* @param chain
* @param authType
* @throws CertificateException
*/
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
/**
* 检查服务器端证书
*
* @param chain
* @param authType
* @throws CertificateException
*/
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
/**
* 返回受信任的X509证书数组
*
* @return
*/
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
8、请求校验工具类
package com.winxin.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* 请求校验工具类
*/
public class SignUtil {
// 与公众接口配置信息中的Token要一致
private static String token = "wsx";
public static boolean checkSignature(String signature, String timestamp, String nonce) {
// 从请求中(也就是微信服务器传过来的)拿到的token, timestamp, nonce
String[] arr = new String[] { token, timestamp, nonce };
// 将token、timestamp、nonce三个参数进行字典序排序
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;
}
// 将加密后的字节数组变成字符串
private static String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}
return strDigest;
}
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;
}
// 用于字典排序
public static void sort(String a[]) {
for (int i = 0; i < a.length - 1; i++) {
for (int j = i + 1; j < a.length; j++) {
if (a[j].compareTo(a[i]) < 0) {
String temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
}
四、微信公众号请求项目的主要controller
package com.wx.controller;
import com.alibaba.fastjson.JSON;
import com.winxin.util.SignUtil;
import com.wx.service.WxEventService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
/**
* 微信相关接口
*
* @author cdj
*
*/
@Controller
@RequestMapping("/WxUser")
public class WxUserController {
@Autowired
private WxEventService wxEventService;
private static final Log LOG = LogFactory.getLog(WxUserController.class);
@RequestMapping("/HandleWxEvent")
public void HandleWxEvent(HttpServletRequest req, HttpServletResponse resp) throws IOException {
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
Map<String, String[]> parameterMap = req.getParameterMap();
System.out.println("requestData:" + JSON.toJSONString(parameterMap));
LOG.info("requestData:" + JSON.toJSONString(parameterMap));
// 微信加密签名
String signature = req.getParameter("signature");
// 时间戳
String timestamp = req.getParameter("timestamp");
// 随机数
String nonce = req.getParameter("nonce");
// 随机字符串
String echostr = req.getParameter("echostr");
System.out.println(
"signature=" + signature + ";timestamp=" + timestamp + ";nonce=" + nonce + ";echostr=" + echostr);
LOG.info("signature=" + signature + ";timestamp=" + timestamp + ";nonce=" + nonce + ";echostr=" + echostr);
PrintWriter out = resp.getWriter();
// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
LOG.info("checkSignature:" + SignUtil.checkSignature(signature, timestamp, nonce));
System.out.println("checkSignature:" + SignUtil.checkSignature(signature, timestamp, nonce));
// 首次请求申请验证,返回echostr
if (echostr != null) {
out.println(echostr);
if (out != null) {
out.close();
}
return;
}
if (SignUtil.checkSignature(signature, timestamp, nonce)) {
System.out.println("success");
LOG.info("success");
String message = "success";
try {
message = wxEventService.processRequest(req);
} catch (Exception e) {
e.printStackTrace();
} finally {
out.println(message);
if (out != null) {
out.close();
}
}
} else {
System.out.println("The request signature is invalid");
LOG.info("The request signature is invalid");
}
}
}
五、还有一个定时任务,因为token的有效期只有7200秒
package com.wx.util;
import com.winxin.util.CommonUtil;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* 创建定时任务实现类
* @description
* @time 2019/3/19
*/
@Component
public class ScheduledTasks {
/**
* 每7100秒执行一次
*/
@Scheduled(fixedRate = 7100000)
public void reportCurrentTime() {
//这个调用的是上面工具类的第一个类中的获取token的方法
CommonUtil.getToken();
}
}
六、
1、serviceImpl层(自己写一下service)
package com.wx.service.impl;
import com.winxin.pojo.Article;
import com.winxin.pojo.NewsMessage;
import com.winxin.pojo.TextMessage;
import com.winxin.util.EventConstant;
import com.winxin.util.MessageUtil;
import com.wx.service.WxEventService;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @className:WxEventServiceImpl
* @description: TODO
* @author: WX
* @date: 2019-03-20 13:01
*/
@Component
@Service
public class WxEventServiceImpl implements WxEventService {
@Override
public String processRequest(HttpServletRequest req) {
String respMessage = null;
try {
// 默认返回的文本消息内容
String respContent = "请求处理异常,请稍候尝试!";
// xml请求解析
Map<String, String> requestMap = MessageUtil.parseXml(req);
// 发送方帐号(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(System.currentTimeMillis());
textMessage.setMsgType(EventConstant.RESP_MESSAGE_TYPE_TEXT);
textMessage.setFuncFlag(0);
// 文本消息
if (msgType.equals(EventConstant.RESP_MESSAGE_TYPE_TEXT)) {
respContent = "您发送的是文本消息!";
}
// 图片消息
else if (msgType.equals(EventConstant.REQ_MESSAGE_TYPE_IMAGE)) {
respContent = "您发送的是图片消息!";
}
// 地理位置消息
else if (msgType.equals(EventConstant.REQ_MESSAGE_TYPE_LOCATION)) {
respContent = "您发送的是地理位置消息!";
}
// 链接消息
else if (msgType.equals(EventConstant.REQ_MESSAGE_TYPE_LINK)) {
respContent = "您发送的是链接消息!";
}
// 音频消息
else if (msgType.equals(EventConstant.REQ_MESSAGE_TYPE_VOICE)) {
respContent = "您发送的是音频消息!";
}
// 事件推送
else if (msgType.equals(EventConstant.REQ_MESSAGE_TYPE_EVENT)) {
// 事件类型
String eventType = requestMap.get("Event");
// 订阅
if (eventType.equals(EventConstant.EVENT_TYPE_SUBSCRIBE)) {
respContent = "谢谢您的关注!";
}
// 取消订阅
else if (eventType.equals(EventConstant.EVENT_TYPE_UNSUBSCRIBE)) {
// 取消订阅后用户再收不到公众号发送的消息,因此不需要回复消息
}
// 自定义菜单点击事件
else if (eventType.equals(EventConstant.EVENT_TYPE_CLICK)) {
// 事件KEY值,与创建自定义菜单时指定的KEY值对应
String eventKey = requestMap.get("EventKey");
if (eventKey.equals("11")) {
respContent = "天气预报菜单项被点击!";
} else if (eventKey.equals("12")) {
respContent = "公交查询菜单项被点击!";
} else if (eventKey.equals("13")) {
respContent = "周边搜索菜单项被点击!";
} else if (eventKey.equals("14")) {
respContent = "历史上的今天菜单项被点击!";
} else if (eventKey.equals("21")) {
respContent = "歌曲点播菜单项被点击!";
} else if (eventKey.equals("22")) {
respContent = "经典游戏菜单项被点击!";
} else if (eventKey.equals("23")) {
respContent = "美女电台菜单项被点击!";
} else if (eventKey.equals("24")) {
respContent = "人脸识别菜单项被点击!";
} else if (eventKey.equals("25")) {
//聊天唠嗑菜单项被点击
NewsMessage newsMessage = new NewsMessage();
newsMessage.setToUserName(fromUserName);
newsMessage.setFromUserName(toUserName);
newsMessage.setCreateTime(System.currentTimeMillis());
newsMessage.setMsgType(EventConstant.RESP_MESSAGE_TYPE_NEWS);
newsMessage.setFuncFlag(0);
List<Article> articleList = new ArrayList<Article>();
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("https://blog.csdn.net/atmknight");
articleList.add(article);
//多图文的话,新建多个article 放入articleList 中即可实现
// 设置图文消息个数
newsMessage.setArticleCount(articleList.size());
// 设置图文消息包含的图文集合
newsMessage.setArticles(articleList);
// 将图文消息对象转换成xml字符串
respMessage = MessageUtil.newsMessageToXml(newsMessage);
return respMessage;
} else if (eventKey.equals("32")) {
respContent = "会员中心菜单项被点击!";
} else if (eventKey.equals("33")) {
respContent = "注册会员菜单项被点击!";
}
}
}
textMessage.setContent(respContent);
respMessage = MessageUtil.textMessageToXml(textMessage);
return respMessage;
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
}
2、我自己写的自定义菜单
package com.wx.service.impl;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.winxin.pojo.Token;
import com.winxin.util.CommonUtil;
import com.winxin.util.Constant;
import com.wx.service.MenuService;
import com.wx.util.WeiXinUtil;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Service;
@Service
public class MenuServiceImpl implements MenuService {
public static Log log = LogFactory.getLog(MenuService.class);
@Override
public JSONObject createMenu(String outputStr) {
return WeiXinUtil.getObject(Constant.POST_CREATE_MENU, outputStr);
}
}
3、还有一个工具类
package com.wx.util;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.winxin.pojo.*;
import com.winxin.util.CommonUtil;
import com.winxin.util.Constant;
import com.wx.service.MenuService;
import net.sf.json.JSONObject;
public class WeiXinUtil {
public static Log log = LogFactory.getLog(MenuService.class);
/**
*这个是从serviceImpl提取出来的公用方法
*/
public static JSONObject getObject(String urlPath, String outputStr) {
String key = Constant.APP_ID + "_" + Constant.APP_SECRET;
Token token = CommonUtil.tokenMap.get(key);
if (token == null) {
log.error("获取token为空,请重新获取");
return null;
} else {
String requestUrl = urlPath.replace("{ACCESSTOKEN}", token.getAccessToken());
return CommonUtil.httpsRequest(requestUrl, "POST", outputStr);
}
}
/**
* 组装菜单数据
* @return
*/
public static Menu getMenu() {
/** -------------------------第一个大按钮--------------------------------------- */
ComplexButton mainBtn1 = new ComplexButton();
mainBtn1.setName("生活助手");
/** -------------------------小按钮--------------------------------------- */
CommonButton btn11 = new CommonButton();
btn11.setName("天气预报");
btn11.setType("click");
btn11.setKey("11");
CommonButton btn12 = new CommonButton();
btn12.setName("公交查询");
btn12.setType("click");
btn12.setKey("12");
CommonButton btn13 = new CommonButton();
btn13.setName("周边搜索");
btn13.setType("click");
btn13.setKey("13");
CommonButton btn14 = new CommonButton();
btn14.setName("历史上的今天");
btn14.setType("click");
btn14.setKey("14");
mainBtn1.setSub_button(new CommonButton[] { btn11, btn12, btn13, btn14 });
/** -------------------------第二个大按钮--------------------------------------- */
ComplexButton mainBtn2 = new ComplexButton();
mainBtn2.setName("休闲驿站");
/** -------------------------小按钮--------------------------------------- */
CommonButton btn21 = new CommonButton();
btn21.setName("歌曲点播");
btn21.setType("click");
btn21.setKey("21");
CommonButton btn22 = new CommonButton();
btn22.setName("经典游戏");
btn22.setType("click");
btn22.setKey("22");
CommonButton btn23 = new CommonButton();
btn23.setName("美女电台");
btn23.setType("click");
btn23.setKey("23");
CommonButton btn24 = new CommonButton();
btn24.setName("人脸识别");
btn24.setType("click");
btn24.setKey("24");
CommonButton btn25 = new CommonButton();
btn25.setName("聊天唠嗑");
btn25.setType("click");
btn25.setKey("25");
mainBtn2.setSub_button(new CommonButton[] { btn21, btn22, btn23, btn24, btn25 });
/** -------------------------第三个大按钮--------------------------------------- */
ComplexButton mainBtn3 = new ComplexButton();
mainBtn3.setName("会员权益");
/** -------------------------小按钮--------------------------------------- */
CommonButton btn32 = new CommonButton();
btn32.setName("会员中心");
btn32.setType("click");
btn32.setKey("32");
CommonButton btn33 = new CommonButton();
btn33.setName("注册会员");
btn33.setType("click");
btn33.setKey("33");
mainBtn3.setSub_button(new CommonButton[] { btn32, btn33 });
Menu menu = new Menu();
menu.setButton(new Button[] { mainBtn1, mainBtn2, mainBtn3 });
return menu;
}
}
感觉写的特别乱,多多包涵。