1.菜单类的封装
根据微信官方文档,我们需要往微信提供的URL发送post请求,并提供如下 JSON格式数据:
因此,我们需要将上述的JSON格式数据封装成一个个对象。
我们创建一个Button 类。该Button类用于封装整个菜单栏(我们可以将公众号底部的菜单栏整个看成一个 零级按钮):
public class Button{
private List<AbstractButton> button = new ArrayList<>();
public List<AbstractButton> getButton() {
return button;
}
public void setButton(List<AbstractButton> button) {
this.button = button;
}
}
上述中的 AbstractButton类是后面所有实体按钮类的父类:
public abstract class AbstractButton {
private String name;
public AbstractButton() {
}
public AbstractButton(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
创建实体按钮类 ClickButton :
public class ClickButton extends AbstractButton{
private String type = "click";
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;
}
public ClickButton() {
}
public ClickButton(String name, String key) {
super(name);
this.key = key;
}
}
创建实体按钮类 ViewButton:
public class ViewButton extends AbstractButton{
private String type = "view";
private String url;
public ViewButton() {
}
public ViewButton(String name, String url) {
super(name);
this.url = url;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
(这里相关功能的菜单按钮只创建了 click和view两种,更多功能按钮可查看微信官方文档。)
用于存放二级按钮的 SubButton:
public class SubButton extends AbstractButton{
private List<AbstractButton> sub_button = new ArrayList<>();
public SubButton() {
}
public SubButton(String name) {
super(name);
}
public List<AbstractButton> getSub_button() {
return sub_button;
}
public void setSub_button(List<AbstractButton> sub_button) {
this.sub_button = sub_button;
}
}
2.菜单的创建
在 CheckUtil 类下,添加向微信服务器发送post请求的方法:
// 以post方式将data数据发送到 Url
public static String post(String url,String data){//data 是要post方式发送出去的json格式数据
try{
URL urlobj = new URL(url);
URLConnection connection = urlobj.openConnection();
//要发送数据出去,必须要设置为可发送数据状态
connection.setDoOutput(true);
//获取数据流
OutputStream os = connection.getOutputStream();
//写出数据
os.write(data.getBytes());
os.close();
//获取输入流
InputStream is = connection.getInputStream();
byte[] b = new byte[1024];
int len;
StringBuilder sb = new StringBuilder();
while ((len=is.read(b))!=-1){
sb.append(new String(b,0,len));
}
return sb.toString();
}catch (Exception e){
e.printStackTrace();
}
return null;
}
创建一个 CreateMenu 类通过运行main方法创建自定义菜单。
public class CreateMenu {
//一般执行一次 ,用于创建微信公众号菜单
public static void main(String[] args) {
Button btn = new Button();
btn.getButton().add( new ClickButton("哈哈哈","11"));
btn.getButton().add( new ViewButton("是不是","https://www.baidu.com/"));
SubButton subButton = new SubButton("内含子菜单");
subButton.getSub_button().add(new ClickButton("哈哈哈sub","11sub") );
subButton.getSub_button().add(new ViewButton("是不是sub","https://www.baidu.com/") );
btn.getButton().add(subButton);
JSONObject jsonObject = JSONObject.fromObject(btn);
System.out.println(jsonObject);
//准备url,需要往该url发送post请求
String url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
//替换 "ACCESS_TOKEN" 为我们自己获取得到的ACCESS_TOKEN
url = url.replace("ACCESS_TOKEN", WeChatService.getAccessToken());
//发送请求
String result = CheckUtil.post(url,jsonObject.toString());
System.out.println(result);
}
}
运行该main方法后,可以看到控制台打印得到的JSON格式字符串:
{"button":
[ {"name":"哈哈哈","type":"click","key":"11"},
{"name":"是不是","type":"view","url":"https://www.baidu.com/"},
{"name":"内含子菜单","sub_button":
[ {"name":"哈哈哈sub","type":"click","key":"11sub"},
{"name":"是不是sub","type":"view","url":"https://www.baidu.com/"}
]
}
]
}
上述创建的是 一个 “哈哈哈”一级菜单click按钮,一个“是不是”一级菜单view按钮,一个“内含子菜单”一级菜单按钮(存放二级按钮 “哈哈哈sub”和“是不是sub”)。
并且打印微信服务器反馈回的result数据如下:
{"errcode":0,"errmsg":"ok"}
这说明创建 菜单成功。效果如下:
新添加:
3. 菜单的响应
我们对 WeChatService 类下的getResponse方法进行修改(添加了处理事件event的方法):
public static String getResponse(Map<String,String> requestMap){
BaseMessage msg = null;
String msgType = requestMap.get("MsgType");
switch(msgType){
case "text"://用户发送到公众号的消息类型若为text,执行该case
msg = Deal.dealTextMessage(requestMap);
break;
case "image":
msg = Deal.dealImageMessage(requestMap);
break;
case "voice":
break;
case "video":
break;
case "shortvideo":
break;
case "location":
break;
case "event"://在公众号的菜单按钮点击之后会返回一个 MsgType为event类型的xml数据
msg = Deal.dealEvent(requestMap);
break;
}
System.out.println("公众号要发送的原始数据:");
System.out.println(msg);
if(msg != null){
return ObjToXml.change(msg);
}else{
return null;
}
}
我们将对数据回复的处理方法dealXXX统一放在Deal这个类中:
public class Deal {
public static BaseMessage dealEvent(Map<String, String> requestMap) {
String event = requestMap.get("Event");
switch (event){
case "CLICK":
return dealClickEvent(requestMap);
case "VIEW" :
return dealVIEWEvent(requestMap);
case "SCAN" :
return dealSCANEvent(requestMap);
}
return null;
}
private static BaseMessage dealSCANEvent(Map<String, String> requestMap) {
return new TextMessage(requestMap,"感谢关注![Hey][Hey]");
}
public static BaseMessage dealVIEWEvent(Map<String, String> requestMap) {
return null;
}
public static BaseMessage dealClickEvent(Map<String, String> requestMap) {
String key = requestMap.get("EventKey");
switch (key){
case "11":
return new TextMessage(requestMap,"你点击的是一级click菜单按钮![加油]") ;
case "11sub":
return new TextMessage(requestMap,"你点击的是二级click菜单按钮![加油]") ;
}
return null;
}
public static BaseMessage dealImageMessage(Map<String, String> requestMap) {
// ImageMessage imageMessage = new ImageMessage(requestMap, "")
return null;
}
public static BaseMessage dealTextMessage(Map<String, String> requestMap) {
TextMessage textMessage = new TextMessage(requestMap,"你真帅![旺柴][旺柴]\uD83C\uDF1D\uD83C\uDF15\uD83C\uDF11\uD83C\uDF1A");
return textMessage;
}
}
至此,就可以对用户的消息进行回复,以及对用户按钮事件进行反馈回复。如下:
ps: 对比新添加前,在subButton下添加了一个 “发图”按钮。将“是不是”都修改为“跳至百度”。