[置顶] 基于springboot+mybatis的微信公众号开发第四篇-自定义菜单的查询、创建、删除及菜单事件响应
2016-12-15 19:13
906 查看
菜单这部分相对来说是简单的,所以做起来很快。
一、看公众号的文档可知有些接口调用可能要https请求,所以这里我们在util包中创建一个书信任管理器类
**二、我们在同个包下的WeixinUtil类,加入用于通用的https请求方法
这里罗列整个类的代码(加上了获取AccessToken的固定方法)**
三、接下来要写实体类了
1、写个AccessToken的实体类吧,以后要用到。
2、然后是菜单的实体类。在model包下创建一个menu包,包下创建Menu类(主要是为了好看)
四、写菜单的逻辑层
1、在service包创建menu包,并在下面创建MenuService
然后再创建实现类MenuServiceImpl
五、在com包下创建一个thread包,再创建AccessTokenThread类,用来定时获取access_token
1、首先在启动类中加入注解@EnableScheduling
2、在AccessTokenThread类中加入
六、在controller包下创建MenuController类,这里是直接组装固定菜单。
六、点击菜单响应事件
因为点击菜单属于事件推送,所以要在CoreServiceImpl类中相应位置新加入对事件推送的处理方法:
1、在接收文本消息前新增菜单id属性
2、在音频消息后面加入事件推送的处理
3、后面我加入了对订阅消息的推送处理。
4、这里给出完整的CoreServiceImpl类
七、如果在仿写过程中出现什么问题或者遗漏什么包,在评论区说下即可。。
一、看公众号的文档可知有些接口调用可能要https请求,所以这里我们在util包中创建一个书信任管理器类
package com.util; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.X509TrustManager; /** * 证书信任管理器(用于https请求) * */ public class MyX509TrustManager implements X509TrustManager { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }
**二、我们在同个包下的WeixinUtil类,加入用于通用的https请求方法
这里罗列整个类的代码(加上了获取AccessToken的固定方法)**
package com.util; import com.model.AccessToken; import net.sf.json.JSONException; import net.sf.json.JSONObject; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.ConnectException; import java.net.URL; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Created by Administrator on 2016/11/7. */ public class WeixinUtil { private static Logger log = LoggerFactory.getLogger(WeixinUtil.class); /** * 发起https请求并获取结果 * * @param requestUrl 请求地址 * @param requestMethod 请求方式(GET、POST) * @param outputStr 提交的数据 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值) */ public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) { JSONObject jsonObject = null; StringBuffer buffer = new StringBuffer(); 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 httpUrlConn = (HttpsURLConnection) url.openConnection(); httpUrlConn.setSSLSocketFactory(ssf); httpUrlConn.setDoOutput(true); httpUrlConn.setDoInput(true); httpUrlConn.setUseCaches(false); // 设置请求方式(GET/POST) httpUrlConn.setRequestMethod(requestMethod); if ("GET".equalsIgnoreCase(requestMethod)) httpUrlConn.connect(); // 当有数据需要提交时 if (null != outputStr) { OutputStream outputStream = httpUrlConn.getOutputStream(); // 注意编码格式,防止中文乱码 outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } // 将返回的输入流转换成字符串 InputStream inputStream = httpUrlConn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } bufferedReader.close(); inputStreamReader.close(); // 释放资源 inputStream.close(); inputStream = null; httpUrlConn.disconnect(); jsonObject = JSONObject.fromObject(buffer.toString()); } catch (ConnectException ce) { log.error("Weixin server connection timed out."); } catch (Exception e) { log.error("https request error:{}", e); } return jsonObject; } // 获取access_token的接口地址(GET) 限200(次/天) public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; /** * 获取access_token * * @param appid 凭证 * @param appsecret 密钥 * @return */ public static AccessToken getAccessToken(String appid, String appsecret) { AccessToken accessToken = null; String requestUrl = access_token_url.replace("APPID", appid).replace("APPSECRET", appsecret); JSONObject jsonObject = httpRequest(requestUrl, "GET", null); // 如果请求成功 if (null != jsonObject) { try { accessToken = new AccessToken(); accessToken.setToken(jsonObject.getString("access_token")); accessToken.setExpiresIn(jsonObject.getInt("expires_in")); } catch (JSONException e) { accessToken = null; // 获取token失败 log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg")); } } return accessToken; } }
三、接下来要写实体类了
1、写个AccessToken的实体类吧,以后要用到。
package com.model; /** * 微信通用接口凭证 * */ public class AccessToken { // 获取到的凭证 private String token; // 凭证有效时间,单位:秒 private int expiresIn; public String getToken() { return token; } public void setToken(String token) { this.token = token; } public int getExpiresIn() { return expiresIn; } public void setExpiresIn(int expiresIn) { this.expiresIn = expiresIn; } }
2、然后是菜单的实体类。在model包下创建一个menu包,包下创建Menu类(主要是为了好看)
package com.model.menu; import java.sql.Timestamp; public class Menu { private String id; private String accountId; private String parentId; private String parentName; private String name; private String type; private String key; private String url; private Integer sort; private String createdBy; private Timestamp createdTime; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getAccountId() { return accountId; } public void setAccountId(String accountId) { this.accountId = accountId; } public String getParentId() { return parentId; } public void setParentId(String parentId) { this.parentId = parentId; } public String getParentName() { return parentName; } public void setParentName(String parentName) { this.parentName = parentName; } public String getName() { return name; } public void setName(String name) { this.name = name; } 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; } public Integer getSort() { return sort; } public void setSort(Integer sort) { this.sort = sort; } public String getCreatedBy() { return createdBy; } public void setCreatedBy(String createdBy) { this.createdBy = createdBy; } public Timestamp getCreatedTime() { return createdTime; } public void setCreatedTime(Timestamp createdTime) { this.createdTime = createdTime; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } }
四、写菜单的逻辑层
1、在service包创建menu包,并在下面创建MenuService
package com.service.menu; import net.sf.json.JSONObject; import java.util.Map; public interface MenuService { public JSONObject getMenu(String accessToken); public int createMenu(Map<String, Object> menu, String accessToken); public int deleteMenu(String accessToken); }
然后再创建实现类MenuServiceImpl
package com.service.menu; import com.model.menu.Menu; import com.util.WeixinUtil; import net.sf.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 对订阅号的菜单的操作 */ @SuppressWarnings("SpringJavaAutowiringInspection") @Service("menuService") public class MenuSeviceImpl implements MenuService { private static Logger log = LoggerFactory.getLogger(MenuSeviceImpl.class); // 菜单创建(POST) 限1000(次/天) public static String menu_create_url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN"; // 菜单查询(POST) 限10000(次/天) public static String menu_get_url = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN"; // 菜单删除(POST) 限1000(次/天) public static String menu_delete_url = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN"; /** * 查询菜单 * * @param accessToken 有效的access_token * @return */ public JSONObject getMenu(String accessToken) { // 拼装创建菜单的url String url = menu_get_url.replace("ACCESS_TOKEN", accessToken); // 调用接口查询菜单 JSONObject jsonObject = WeixinUtil.httpRequest(url, "GET", null); return jsonObject; } /** * 创建菜单(替换旧菜单) * * @param accessToken 有效的access_token * @return 0表示成功,其他值表示失败 */ public int createMenu(Map<String, Object> menu,String accessToken) { int result = 0; // 拼装创建菜单的url String url = menu_create_url.replace("ACCESS_TOKEN", accessToken); // 将菜单对象转换成json字符串 String jsonMenu = JSONObject.fromObject(menu).toString(); // 调用接口创建菜单 JSONObject jsonObject = WeixinUtil.httpRequest(url, "POST", jsonMenu); if (null != jsonObject) { if (0 != jsonObject.getInt("errcode")) { result = jsonObject.getInt("errcode"); log.error("创建菜单失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg")); log.error("****"+jsonMenu+"****"); } } return result; } /** * 删除菜单 * * @param accessToken 有效的access_token * @return 0表示成功,其他值表示失败 */ public int deleteMenu(String accessToken) { int result = 0; // 拼装创建菜单的url String url = menu_delete_url.replace("ACCESS_TOKEN", accessToken); // 调用接口创建菜单 JSONObject jsonObject = WeixinUtil.httpRequest(url, "POST", null); if (null != jsonObject) { if (0 != jsonObject.getInt("errcode")) { result = jsonObject.getInt("errcode"); log.error("删除菜单失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg")); } } return result; } }
五、在com包下创建一个thread包,再创建AccessTokenThread类,用来定时获取access_token
1、首先在启动类中加入注解@EnableScheduling
package com; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableScheduling // 这里,启用定时任务 public class WeixinMpApplication { public static void main(String[] args) { SpringApplication.run(WeixinMpApplication.class, args); } }
2、在AccessTokenThread类中加入
package com.thread; import com.model.accesstoken.AccessToken; import com.util.WeixinUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; /** * 定时获取微信access_token的线程 *在WechatMpDemoApplication中注解@EnableScheduling,在程序启动时就开启定时任务。 * 每7200秒执行一次 */ @Component public class AccessTokenThread { private static Logger log = LoggerFactory.getLogger(AccessTokenThread.class); // 第三方用户唯一凭证 public static String appid = "wx1dd7aa8ed2be67e7"; // 第三方用户唯一凭证密钥 public static String appsecret = "ae9d55c58f0d87208f63eb229eb74926"; // 第三方用户唯一凭证 public static AccessToken accessToken = null; @Scheduled(fixedDelay = 2*3600*1000) //7200秒执行一次 public void gettoken(){ accessToken= WeixinUtil.getAccessToken(appid,appsecret); if(null!=accessToken){ log.info("获取成功,accessToken:"+accessToken.getToken()); }else { log.error("获取token失败"); } } }
六、在controller包下创建MenuController类,这里是直接组装固定菜单。
package com.controller; import com.model.menu.Menu; import com.service.menu.MenuService; import com.thread.AccessTokenThread; import net.sf.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * * 对订阅号的菜单的操作 * */ @RestController @RequestMapping("/menu") public class MenuController { @Autowired private MenuService menuService; private static Logger log = LoggerFactory.getLogger(MenuController.class); //查询全部菜单 @RequestMapping(value = "/get",method = RequestMethod.GET) public String getMenu() { // 调用接口获取access_token String at = AccessTokenThread.accessToken.getToken(); JSONObject jsonObject =null; if (at != null) { // 调用接口查询菜单 jsonObject = menuService.getMenu(at); // 判断菜单创建结果 return String.valueOf(jsonObject); } log.info("token为"+at); return "无数据"; } //创建菜单 @RequestMapping(value = "/create",method = RequestMethod.POST) public int createMenu() { // 调用接口获取access_token String at = AccessTokenThread.accessToken.getToken(); int result=0; if (at != null) { // 调用接口创建菜单 result = menuService.createMenu(getFirstMenu(),at); // 判断菜单创建结果 if (0 == result) { log.info("菜单创建成功!"); } else { log.info("菜单创建失败,错误码:" + result); } } return result ; } //删除菜单 @RequestMapping(value = "/delete",method = RequestMethod.POST) public int deleteMenu() { // 调用接口获取access_token String at = AccessTokenThread.accessToken.getToken(); int result=0; if (at != null) { // 删除菜单 result = menuService.deleteMenu(at); // 判断菜单删除结果 if (0 == result) { log.info("菜单删除成功!"); } else { log.info("菜单删除失败,错误码:" + result); } } return result; } /** * 组装菜单数据 */ public static Map<String, Object> getFirstMenu(){ //第一栏菜单 Menu menu1=new Menu(); menu1.setId("1"); menu1.setName("第一栏"); menu1.setType("click"); menu1.setKey("1"); Menu menu11=new Menu(); menu11.setId("11"); menu11.setName("第一栏的第一个v3"); menu11.setType("click"); menu11.setKey("11"); Menu menu12=new Menu(); menu12.setId("12"); menu12.setName("第一栏的第二个"); menu12.setType("click"); menu12.setKey("12"); //第二栏 Menu menu2=new Menu(); menu2.setId("2"); menu2.setName("第二栏"); menu2.setType("click"); menu2.setKey("2"); Menu menu21=new Menu(); menu21.setId("21"); menu21.setName("第二栏的第一个"); menu21.setType("click"); menu21.setKey("21"); Menu menu3=new Menu(); menu3.setId("3"); menu3.setName("第三栏"); menu3.setType("view"); menu3.setUrl("http://www.baidu.com"); //最外一层大括号 Map<String, Object> wechatMenuMap = new HashMap<String, Object>(); //包装button的List List<Map<String, Object>> wechatMenuMapList = new ArrayList<Map<String, Object>>(); //包装第一栏 Map<String, Object> menuMap1 = new HashMap<String, Object>(); Map<String, Object> menuMap11 = new HashMap<String, Object>(); Map<String, Object> menuMap12 = new HashMap<String, Object>(); List<Map<String, Object>> subMenuMapList1 = new ArrayList<Map<String, Object>>(); //第一栏第一个 menuMap11.put("name",menu11.getName()); menuMap11.put("type",menu11.getType()); menuMap11.put("key",menu11.getKey()); subMenuMapList1.add(menuMap11); //第二栏第二个 menuMap12.put("name",menu12.getName()); menuMap12.put("type",menu12.getType()); menuMap12.put("key",menu12.getKey()); subMenuMapList1.add(menuMap12); menuMap1.put("name",menu1.getName()); menuMap1.put("sub_button",subMenuMapList1); //包装第二栏 Map<String, Object> menuMap2 = new HashMap<String, Object>(); Map<String, Object> menuMap21 = new HashMap<String, Object>(); List<Map<String, Object>> subMenuMapList2 = new ArrayList<Map<String, Object>>(); //第二栏第一个 menuMap21.put("name",menu21.getName()); menuMap21.put("type",menu21.getType()); menuMap21.put("key",menu21.getKey()); subMenuMapList2.add(menuMap21); menuMap2.put("name",menu2.getName()); menuMap2.put("sub_button",subMenuMapList2); //包装第三栏 Map<String, Object> menuMap3 = new HashMap<String, Object>(); List<Map<String, Object>> subMenuMapList3 = new ArrayList<Map<String, Object>>(); menuMap3.put("name",menu3.getName()); menuMap3.put("type",menu3.getType()); menuMap3.put("url",menu3.getUrl()); menuMap3.put("sub_button",subMenuMapList3); wechatMenuMapList.add(menuMap1); wechatMenuMapList.add(menuMap2); wechatMenuMapList.add(menuMap3); wechatMenuMap.put("button",wechatMenuMapList); return wechatMenuMap; } }
六、点击菜单响应事件
因为点击菜单属于事件推送,所以要在CoreServiceImpl类中相应位置新加入对事件推送的处理方法:
1、在接收文本消息前新增菜单id属性
//点击菜单id String EventKey =requestMap.get("EventKey"); // 接收文本消息内容 String content = requestMap.get("Content");
2、在音频消息后面加入事件推送的处理
// 事件推送 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) { // 事件类型 String eventType =requestMap.get("Event"); // 自定义菜单点击事件 if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) { switch (EventKey){ case "11":{ respContent = "这是第一栏第一个"; break; } case "12":{ respContent = "这是第一栏第一个"; break; } case "21":{ respContent = "这是第二栏第一个"; break; } default:{ log.error("开发者反馈:EventKey值没找到,它是:"+EventKey); respContent= "很抱歉,此按键功能正在升级无法使用"; } } textMessage.setContent(respContent); // 将文本消息对象转换成xml字符串 respMessage = MessageUtil.textMessageToXml(textMessage); } else if(eventType.equals(MessageUtil.EVENT_TYPE_VIEW)){ // 对于点击菜单转网页暂时不做推送 } }
3、后面我加入了对订阅消息的推送处理。
// 订阅 else if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) { //测试单图文回复 Article article = new Article(); article.setTitle("谢谢您的关注!"); // 图文消息中可以使用QQ表情、符号表情 article.setDescription("点击图文可以跳转到百度首页"); // 将图片置为空 article.setPicUrl("http://www.sinaimg.cn/dy/slidenews/31_img/2016_38/28380_733695_698372.jpg"); article.setUrl("http://www.baidu.com"); articleList.add(article); newsMessage.setArticleCount(articleList.size()); newsMessage.setArticles(articleList); respMessage = MessageUtil.newsMessageToXml(newsMessage); } else if(eventType.equals(MessageUtil.EVENT_TYPE_SCAN)){ //测试单图文回复 Article article = new Article(); article.setTitle("这是已关注用户扫描二维码弹到的界面"); // 图文消息中可以使用QQ表情、符号表情 article.setDescription("点击图文可以跳转到百度首页"); // 将图片置为空 article.setPicUrl("http://www.sinaimg.cn/dy/slidenews/31_img/2016_38/28380_733695_698372.jpg"); article.setUrl("http://www.baidu.com"); articleList.add(article); newsMessage.setArticleCount(articleList.size()); newsMessage.setArticles(articleList); respMessage = MessageUtil.newsMessageToXml(newsMessage); } // 取消订阅 else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) { // TODO 取消订阅后用户再收不到公众号发送的消息,因此不需要回复消息 }
4、这里给出完整的CoreServiceImpl类
package com.service.core;
import com.model.message.response.Article;
import com.model.message.response.NewsMessage;
import com.model.message.response.TextMessage;
import com.util.MessageUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 核心服务类
*/
@Service("coreService")
public class CoreServiceImpl implements CoreService {
private static Logger log = LoggerFactory.getLogger(CoreServiceImpl.class);
/**
* 处理微信发来的请求(包括事件的推送)
*
* @param request
* @return
*/
public String processRequest(HttpServletRequest request) {
String respMessage = null;
try {
// 默认返回的文本消息内容
String respContent = "请求处理异常,请稍候尝试!";
// xml请求解析
Map<String, String> requestMap = MessageUtil.parseXml(request);
// 发送方帐号(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(new Date().getTime());
textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);
textMessage.setFuncFlag(0);
// 创建图文消息
NewsMessage newsMessage = new NewsMessage();
newsMessage.setToUserName(fromUserName);
newsMessage.setFromUserName(toUserName);
newsMessage.setCreateTime(new Date().getTime());
newsMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_NEWS);
newsMessage.setFuncFlag(0);
List<Article> articleList = new ArrayList<Article>();
//点击菜单id
String EventKey =requestMap.get("EventKey");
// 接收文本消息内容
String content = requestMap.get("Content");
// 自动回复文本消息
if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
//如果用户发送表情,则回复同样表情。
if (isQqFace(content)) {
respContent = content;
textMessage.setContent(respContent);
// 将文本消息对象转换成xml字符串
respMessage = MessageUtil.textMessageToXml(textMessage);
} else {
//回复固定消息
switch (content) {
case "1": {
StringBuffer buffer = new StringBuffer();
buffer.append("您好,我是小8,请回复数字选择服务:").append("\n\n");
buffer.append("11 可查看测试单图文").append("\n");
buffer.append("12 可测试多图文发送").append("\n");
buffer.append("13 可测试网址").append("\n");
buffer.append("或者您可以尝试发送表情").append("\n\n");
buffer.append("回复“1”显示此帮助菜单").append("\n");
respContent = String.valueOf(buffer);
textMessage.setContent(respContent);
respMessage = MessageUtil.textMessageToXml(textMessage);
break;
}
case "11": {
//测试单图文回复
Article article = new Article();
article.setTitle("微信公众帐号开发教程Java版");
// 图文消息中可以使用QQ表情、符号表情
article.setDescription("这是测试有没有换行\n\n如果有空行就代表换行成功\n\n点击图文可以跳转到百度首页");
// 将图片置为空
article.setPicUrl("http://www.sinaimg.cn/dy/slidenews/31_img/2016_38/28380_733695_698372.jpg");
article.setUrl("http://www.baidu.com");
articleList.add(article);
newsMessage.setArticleCount(articleList.size());
newsMessage.setArticles(articleList);
respMessage = MessageUtil.newsMessageToXml(newsMessage);
break;
}
case "12": {
//多图文发送
Article article1 = new Article();
article1.setTitle("紧急通知,不要捡这种钱!湛江都已经传疯了!\n");
article1.setDescription("");
article1.setPicUrl("http://www.sinaimg.cn/dy/slidenews/31_img/2016_38/28380_733695_698372.jpg");
article1.setUrl("http://mp.weixin.qq.com/s?__biz=MjM5Njc2OTI4NQ==&mid=2650924309&idx=1&sn=8bb6ae54d6396c1faa9182a96f30b225&chksm=bd117e7f8a66f769dc886d38ca2d4e4e675c55e6a5e01e768b383f5859e09384e485da7bed98&scene=4#wechat_redirect");
Article article2 = new Article();
article2.setTitle("湛江谁有这种女儿,请给我来一打!");
article2.setDescription("");
article2.setPicUrl("http://www.sinaimg.cn/dy/slidenews/31_img/2016_38/28380_733695_698372.jpg");
article2.setUrl("http://mp.weixin.qq.com/s?__biz=MjM5Njc2OTI4NQ==&mid=2650924309&idx=2&sn=d7ffc840c7e6d91b0a1c886b16797ee9&chksm=bd117e7f8a66f7698d094c2771a1114853b97dab9c172897c3f9f982eacb6619fba5e6675ea3&scene=4#wechat_redirect");
Article article3 = new Article();
article3.setTitle("以上图片我就随意放了");
article3.setDescription("");
article3.setPicUrl("http://www.sinaimg.cn/dy/slidenews/31_img/2016_38/28380_733695_698372.jpg");
article3.setUrl("http://mp.weixin.qq.com/s?__biz=MjM5Njc2OTI4NQ==&mid=2650924309&idx=3&sn=63e13fe558ff0d564c0da313b7bdfce0&chksm=bd117e7f8a66f7693a26853dc65c3e9ef9495235ef6ed6c7796f1b63abf1df599aaf9b33aafa&scene=4#wechat_redirect");
articleList.add(article1);
articleList.add(article2);
articleList.add(article3);
newsMessage.setArticleCount(articleList.size());
newsMessage.setArticles(articleList);
respMessage = MessageUtil.newsMessageToXml(newsMessage);
break;
}
case "13": {
//测试网址回复
respContent = "<a href=\"http://www.baidu.com\">百度主页</a>";
textMessage.setContent(respContent);
// 将文本消息对象转换成xml字符串
respMessage = MessageUtil.textMessageToXml(textMessage);
break;
}
default: {
respContent = "(这是里面的)很抱歉,现在小8暂时无法提供此功能给您使用。\n\n回复“1”显示帮助信息";
textMessage.setContent(respContent);
// 将文本消息对象转换成xml字符串
respMessage = MessageUtil.textMessageToXml(textMessage);
}
}
}
}
// 图片消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {
respContent = "您发送的是图片消息!";
textMessage.setContent(respContent);
// 将文本消息对象转换成xml字符串
respMessage = MessageUtil.textMessageToXml(textMessage);
}
// 地理位置消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {
respContent = "您发送的是地理位置消息!";
textMessage.setContent(respContent);
// 将文本消息对象转换成xml字符串
respMessage = MessageUtil.textMessageToXml(textMessage);
}
// 链接消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) {
respContent = "您发送的是链接消息!";textMessage.setContent(respContent);
// 将文本消息对象转换成xml字符串
respMessage = MessageUtil.textMessageToXml(textMessage);
}
// 音频消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) {
respContent = "您发送的是音频消息!";
textMessage.setContent(respContent);
// 将文本消息对象转换成xml字符串
respMessage = MessageUtil.textMessageToXml(textMessage);
}
// 事件推送
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {
// 事件类型
String eventType =requestMap.get("Event");
// 自定义菜单点击事件
if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) {
switch (EventKey){
case "11":{
respContent = "这是第一栏第一个";
break;
}
case "12":{
respContent = "这是第一栏第一个";
break;
}
case "21":{
respContent = "这是第二栏第一个";
break;
}
default:{
log.error("开发者反馈:EventKey值没找到,它是:"+EventKey);
respContent= "很抱歉,此按键功能正在升级无法使用";
}
}
textMessage.setContent(respContent);
// 将文本消息对象转换成xml字符串
respMessage = MessageUtil.textMessageToXml(textMessage);
}
else if(eventType.equals(MessageUtil.EVENT_TYPE_VIEW)){
// 对于点击菜单转网页暂时不做推送
}
// 订阅 else if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) { //测试单图文回复 Article article = new Article(); article.setTitle("谢谢您的关注!"); // 图文消息中可以使用QQ表情、符号表情 article.setDescription("点击图文可以跳转到百度首页"); // 将图片置为空 article.setPicUrl("http://www.sinaimg.cn/dy/slidenews/31_img/2016_38/28380_733695_698372.jpg"); article.setUrl("http://www.baidu.com"); articleList.add(article); newsMessage.setArticleCount(articleList.size()); newsMessage.setArticles(articleList); respMessage = MessageUtil.newsMessageToXml(newsMessage); } else if(eventType.equals(MessageUtil.EVENT_TYPE_SCAN)){ //测试单图文回复 Article article = new Article(); article.setTitle("这是已关注用户扫描二维码弹到的界面"); // 图文消息中可以使用QQ表情、符号表情 article.setDescription("点击图文可以跳转到百度首页"); // 将图片置为空 article.setPicUrl("http://www.sinaimg.cn/dy/slidenews/31_img/2016_38/28380_733695_698372.jpg"); article.setUrl("http://www.baidu.com"); articleList.add(article); newsMessage.setArticleCount(articleList.size()); newsMessage.setArticles(articleList); respMessage = MessageUtil.newsMessageToXml(newsMessage); } // 取消订阅 else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) { // TODO 取消订阅后用户再收不到公众号发送的消息,因此不需要回复消息 }
}
} catch (Exception e) {
e.printStackTrace();
}
return respMessage;
}
/**
* 判断是否是QQ表情
*
* @param content
* @return
*/
public static boolean isQqFace(String content) {
boolean result = false;
// 判断QQ表情的正则表达式
String qqfaceRegex = "/::\\)|/::~|/::B|/::\\||/:8-\\)|/::<|/::$|/::X|/::Z|/::'\\(|/::-\\||/::@|/::P|/::D|/::O|/::\\(|/::\\+|/:--b|/::Q|/::T|/:,@P|/:,@-D|/::d|/:,@o|/::g|/:\\|-\\)|/::!|/::L|/::>|/::,@|/:,@f|/::-S|/:\\?|/:,@x|/:,@@|/::8|/:,@!|/:!!!|/:xx|/:bye|/:wipe|/:dig|/:handclap|/:&-\\(|/:B-\\)|/:<@|/:@>|/::-O|/:>-\\||/:P-\\(|/::'\\||/:X-\\)|/::\\*|/:@x|/:8\\*|/:pd|/:<W>|/:beer|/:basketb|/:oo|/:coffee|/:eat|/:pig|/:rose|/:fade|/:showlove|/:heart|/:break|/:cake|/:li|/:bome|/:kn|/:footb|/:ladybug|/:shit|/:moon|/:sun|/:gift|/:hug|/:strong|/:weak|/:share|/:v|/:@\\)|/:jj|/:@@|/:bad|/:lvu|/:no|/:ok|/:love|/:<L>|/:jump|/:shake|/:<O>|/:circle|/:kotow|/:turn|/:skip|/:oY|/:#-0|/:hiphot|/:kiss|/:<&|/:&>";
Pattern p = Pattern.compile(qqfaceRegex);
Matcher m = p.matcher(content);
if (m.matches()) {
result = true;
}
return result;
}
}
七、如果在仿写过程中出现什么问题或者遗漏什么包,在评论区说下即可。。
相关文章推荐
- [置顶] 基于springboot+mybatis的微信公众号开发第一篇-基本架构
- 微信公众号开发---自定义菜单的创建及菜单事件响应(java)
- [置顶] 基于springboot+mybatis的微信公众号开发第二篇-验证与消息推送的基本设置
- [置顶] 基于springboot+mybatis的微信公众号开发第三篇-消息的接收与回复
- 微信公众帐号开发教程第14篇-自定义菜单的创建及菜单事件响应
- [038] 微信公众帐号开发教程第14篇-自定义菜单的创建及菜单事件响应
- [038] 微信公众帐号开发教程第14篇-自定义菜单的创建及菜单事件响应
- 微信公众帐号开发教程第14篇-自定义菜单的创建及菜单事件响应
- 微信公众帐号开发教程第14篇-自定义菜单的创建及菜单事件响应
- 微信公众帐号开发教程第14篇-自定义菜单的创建及菜单事件响应
- 微信公众帐号开发教程第14篇-自定义菜单的创建及菜单事件响应
- [038] 微信公众帐号开发教程第14篇-自定义菜单的创建及菜单事件响应 .
- 微信公众帐号开发教程第14篇-自定义菜单的创建及菜单事件响应
- 微信公众帐号开发教程第14篇-自定义菜单的创建及菜单事件响应
- 微信公众帐号开发教程第14篇-自定义菜单的创建及菜单事件响应
- 微信公众帐号开发教程第14篇-自定义菜单的创建及菜单事件响应
- 微信公众帐号自定义菜单创建及事件响应开发教程 附源代码(转)
- 微信公众帐号开发教程第14篇-自定义菜单的创建及菜单事件响应
- 微信公众帐号开发教程第14篇-自定义菜单的创建及菜单事件响应
- [038] 微信公众帐号开发教程第14篇-自定义菜单的创建及菜单事件响应