菜单这部分相对来说是简单的,所以做起来很快。
一、看公众号的文档可知有些接口调用可能要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;
}
}
七、如果在仿写过程中出现什么问题或者遗漏什么包,在评论区说下即可。。