微信公众号(卡券) A Little Demo

2023-12-27 11:50
文章标签 微信 公众 demo little 卡券

本文主要是介绍微信公众号(卡券) A Little Demo,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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;@Overrideprotected 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*/@Overridepublic void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}/*** 检查服务器端证书** @param chain* @param authType* @throws CertificateException*/@Overridepublic void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}/*** 返回受信任的X509证书数组** @return*/@Overridepublic 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, nonceString[] 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 {@Autowiredprivate 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));// 首次请求申请验证,返回echostrif (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 {@Overridepublic 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);@Overridepublic 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;}
}

感觉写的特别乱,多多包涵。

这篇关于微信公众号(卡券) A Little Demo的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/543040

相关文章

W外链微信推广短连接怎么做?

制作微信推广链接的难点分析 一、内容创作难度 制作微信推广链接时,首先需要创作有吸引力的内容。这不仅要求内容本身有趣、有价值,还要能够激起人们的分享欲望。对于许多企业和个人来说,尤其是那些缺乏创意和写作能力的人来说,这是制作微信推广链接的一大难点。 二、精准定位难度 微信用户群体庞大,不同用户的需求和兴趣各异。因此,制作推广链接时需要精准定位目标受众,以便更有效地吸引他们点击并分享链接

uniapp设置微信小程序的交互反馈

链接:uni.showToast(OBJECT) | uni-app官网 (dcloud.net.cn) 设置操作成功的弹窗: title是我们弹窗提示的文字 showToast是我们在加载的时候进入就会弹出的提示。 2.设置失败的提示窗口和标签 icon:'error'是设置我们失败的logo 设置的文字上限是7个文字,如果需要设置的提示文字过长就需要设置icon并给

linux 内核提权总结(demo+exp分析) -- 任意读写(四)

hijack_modprobe_path篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm     原理同hijack_prctl, 当用户执行错误格式的elf文件时内核调用call_usermod

linux 内核提权总结(demo+exp分析) -- 任意读写(三)

hijack_prctl篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm   prctl函数: 用户态函数,可用于定制进程参数,非常适合和内核进行交互 用户态执行prctl函数后触发prctl系统

linux 内核提权总结(demo+exp分析) -- 任意读写(二)

hijack_vdso篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm     vdso: 内核实现的一个动态库,存在于内核,然后映射到用户态空间,可由用户态直接调用 内核中的vdso如果被修改

linux 内核提权总结(demo+exp分析) -- 任意读写(一)

cred篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm   每个线程在内核中都对应一个线程结构块thread_infothread_info中存在task_struct类型结构体 struct t

linux 内核提权总结(demo+exp分析) -- ROP(二)

ret2usr CR4篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm   smep: smep是内核的一种保护措施, 使得内核不可执行用户态代码 内核通过CR4寄存器的第20位来控制smep,

linux 内核提权总结(demo+exp分析) -- ROP(一)

基础ROP篇(linux 5.0.21) 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm   内核提权与用户态攻击的区别 攻击流程 用户态攻击: 执行 system("/bin/sh") 获得shel

实例demo理解面向接口思想

浅显的理解面向接口编程 Android开发的语言是java,至少目前是,所以理解面向接口的思想是有必要的。下面通过一个简单的例子来理解。具体的概括我也不知道怎么说。 例子: 现在我们要开发一个应用,模拟移动存储设备的读写,即计算机与U盘、MP3、移动硬盘等设备进行数据交换。已知要实现U盘、MP3播放器、移动硬盘三种移动存储设备,要求计算机能同这三种设备进行数据交换,并且以后可能会有新的第三方的

基于微信小程序与嵌入式系统的智能小车开发(详细流程)

一、项目概述 本项目旨在开发一款智能小车,结合微信小程序与嵌入式系统,提供实时图像处理与控制功能。用户可以通过微信小程序远程操控小车,并实时接收摄像头采集的图像。该项目解决了传统遥控小车在图像反馈和控制延迟方面的问题,提升了小车的智能化水平,适用于教育、科研和娱乐等多个领域。 二、系统架构 1. 系统架构设计 本项目的系统架构主要分为以下几个部分: 微信小程序:负责用户界面、控制指令的