第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > 微信公众号自动回复-底部菜单栏-关键字回复-回复2条消息(1文字 1图片)

微信公众号自动回复-底部菜单栏-关键字回复-回复2条消息(1文字 1图片)

时间:2021-01-23 22:53:50

相关推荐

微信公众号自动回复-底部菜单栏-关键字回复-回复2条消息(1文字 1图片)

微信公众号自动回复-底部菜单栏-关键字回复-回复2条消息(1文字,1图片)JAVA

主要实现:1.关注后自动回复文字内容2.关键字回复图文消息3.实现公众号自定义底部菜单栏 - 点击菜单栏进入链接, 点击菜单栏回复图文消息, 点击菜单栏回复2条消息(一条文字, 一条图片)主要参考: /a/1190000015715950

1. 前提准备

需要可以接收微信发来的XML可以参考上一篇博文:/yuanpeij/article/details/120776759

2. 关注后自动回复文字

/*** 接收微信的事件*/@PostMapping(value = "/weixinVerify", produces = "application/xml")public void weixinVerify(HttpServletRequest request, HttpServletResponse response) throws Exception {response.setContentType("text/html; charset=utf-8");response.setContentType("application/xml; charset=utf-8");PageData pageData = this.getPageData();String method = request.getMethod();if ("POST".equals(method)) {String xmlStr = "";String msgrsp = "";PrintWriter out = response.getWriter();try {//解析微信发来的XMLxmlStr = XmlUtil.inputStream2StringNew(request.getInputStream());Map<String, String> requestMap = XmlUtil.parseXml(xmlStr);//消息类型 -- 事件(event)if (MessageUtil.REQ_MESSAGE_TYPE_EVENT.equals(requestMap.get("msgType"))) {//关注(subscribe)if (MessageUtil.EVENT_TYPE_SUBSCRIBE.equals(requestMap.get("event"))) {String openid = requestMap.get("fromUserName"); //用户openidString mpid = requestMap.get("toUserName"); //公众号原始ID//普通文本消息BaseMessage txtmsg = new BaseMessage();txtmsg.setToUserName(openid);txtmsg.setFromUserName(mpid);txtmsg.setCreateTime(new Date().getTime());txtmsg.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);txtmsg.setContent("您好,欢迎关注!");//文本转xmlString msgrsp = MessageUtil.textMessageToXml(txtmsg);}}out.print(msgrsp);out.close();} catch (Exception e) {logger.error("消息事件接收失败");e.printStackTrace();}}}

需要的jar

<!-- hutool工具集 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.3.9</version></dependency><!-- 阿里JSON解析器 --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.70</version></dependency><dependency><groupId>com.thoughtworks.xstream</groupId><artifactId>xstream</artifactId><version>1.4.9</version></dependency>

BaseMessage

@Datapublic class BaseMessage {//接收方账号(收到的OpenID)private String ToUserName;//开发者微信号(公众号)private String FromUserName;//消息创建时间(整形)private long CreateTime;//消息类型(text,image,location,link,voice)private String MsgType;//返回内容private String Content;//返回的图片idprivate String MediaId;}

BaseButton

@Datapublic class BasicButton {private String name;private String type;}

ViewButton

/*** @Description: 直接进入链接的按钮*/@Datapublic class ViewButton extends BasicButton {private String url;}

CommonButton

/*** @Description: 点击的按钮*/@Datapublic class CommonButton extends BasicButton {private String key;}

父按钮

/*** @Description: 父按钮*/@Datapublic class ComplexButton extends BasicButton {private BasicButton[] sub_button;}

菜单

/*** @Description: 菜单*/@Datapublic class Menu {private BasicButton[] button;}

MessageUtil

import java.io.*;import .URL;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.regex.Matcher;import java.util.regex.Pattern;import .ssl.HttpsURLConnection;import javax.servlet.http.HttpServletRequest;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import mon.utils.weixin.*;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader;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;public class MessageUtil {/*** 返回消息类型:文本*/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 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_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";/*** 事件类型:自己设置的KEY*/public static final String KEY = "设置什么KEY, 监听到什么值";// 菜单创建(POST) 限100(次/天)public static String MENU_CREATE_RUL = "https://api./cgi-bin/menu/create?access_token=ACCESS_TOKEN";/*** 解析微信发来的请求(XML)* * @param request* @return* @throws Exception*/@SuppressWarnings("unchecked")public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {// 将解析结果存储在HashMap中Map<String, String> map = new HashMap<String, String>();// 从request中取得输入流InputStream inputStream = request.getInputStream();// 读取输入流SAXReader reader = new SAXReader();Document document = reader.read(inputStream);// 得到xml根元素Element root = document.getRootElement();// 得到根元素的所有子节点List<Element> elementList = root.elements();// 遍历所有子节点for (Element e : elementList)map.put(e.getName(), e.getText());// 释放资源inputStream.close();inputStream = null;return map;}/*** 扩展xstream,使其支持CDATA块* * @date -01-15*/private static XStream xstream = new XStream(new XppDriver() {public HierarchicalStreamWriter createWriter(Writer out) {return new PrettyPrintWriter(out) {// 对所有xml节点的转换都增加CDATA标记boolean cdata = true;@SuppressWarnings("unchecked")public void startNode(String name, Class clazz) {super.startNode(name, clazz);}protected void writeText(QuickWriter writer, String text) {if (cdata) {writer.write("<![CDATA[");writer.write(text);writer.write("]]>");} else {writer.write(text);}}};}});/*** 文本转xml*/public static String textMessageToXml(BaseMessage baseMessage) {xstream.alias("xml", baseMessage.getClass());return xstream.toXML(baseMessage);}/*** 图文转xml*/public static String newsMessageToXml(BaseMessage baseMessage) {xstream.alias("xml", baseMessage.getClass());xstream.alias("item", new Article().getClass());return xstream.toXML(baseMessage);}/*** 图片转xml*/public static String imageMessageToXml(ImageMessage imageMessage) {xstream.alias("xml", imageMessage.getClass());return xstream.toXML(imageMessage);}/*** 发送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 {URL url = new URL(requestUrl);HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();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.parseObject(buffer.toString());} catch (Exception e) {e.printStackTrace();}return jsonObject;}/*** 组装菜单数据(父子菜单栏), 直接拉到底下看父菜单* 1.如果菜单类型是:view, 点击菜单则会进入到url中(进入链接)* 2.类型是:click, 点击, 微信会传入XML, 里面有"eventKey"字段, 对应你设置的MessageUtil.KEY(监听到"eventKey"= 你设置的key)*/public static Menu getMenu() {//左边的菜单栏------------------ViewButton btn11 = new ViewButton();btn11.setName("资讯月刊");btn11.setType("view");btn11.setUrl("/yuanpeij/article/details/120776759");CommonButton btn12 = new CommonButton();btn12.setName("行业动态");btn12.setType("click");btn12.setKey(MessageUtil.KEY);CommonButton btn13 = new CommonButton();btn13.setName("XX动态");btn13.setType("click");btn13.setKey(MessageUtil.KEY);//中间的菜单栏-------------ViewButton btn21 = new ViewButton();btn21.setName("专业研究");btn21.setType("view");btn21.setUrl("/yuanpeij/article/details/120776759");ViewButton btn22 = new ViewButton();btn22.setName("XX观点");btn22.setType("view");btn22.setUrl("/yuanpeij/article/details/120776759");ViewButton btn23 = new ViewButton();btn23.setName("主题演讲");btn23.setType("view");btn23.setUrl("/yuanpeij/article/details/120776759");//右边的菜单栏-------------CommonButton btn31 = new CommonButton();btn31.setName("XX简介");btn31.setType("click");btn31.setKey(MessageUtil.KEY);CommonButton btn32 = new CommonButton();btn32.setName("业务类型");btn32.setType("click");btn32.setKey(MessageUtil.KEY);CommonButton btn33 = new CommonButton();btn33.setName("招贤纳士");btn33.setType("click");btn33.setKey(MessageUtil.KEY);CommonButton btn34 = new CommonButton();btn34.setName("XX路线");btn34.setType("click");btn34.setKey(MessageUtil.KEY);CommonButton btn35 = new CommonButton();btn35.setName("XXXX");btn35.setType("click");btn35.setKey(MessageUtil.KEY);//三个主菜单栏, 底下包含各自的子菜单ComplexButton mainBtn1 = new ComplexButton();mainBtn1.setName("XX资讯");mainBtn1.setSub_button(new BasicButton[] {btn11, btn12, btn13});ComplexButton mainBtn2 = new ComplexButton();mainBtn2.setName("专业分享");mainBtn2.setSub_button(new BasicButton[] {btn21, btn22, btn23});ComplexButton mainBtn3 = new ComplexButton();mainBtn3.setName("关于XX");mainBtn3.setSub_button(new BasicButton[] {btn31, btn32, btn33, btn34, btn35});Menu menu = new Menu();menu.setButton(new BasicButton[] {mainBtn1, mainBtn2, mainBtn3});return menu;}/*** 创建菜单** @param menu 菜单实例* @param accessToken 有效的access_token* @return 0表示成功,其他值表示失败*/public static int createMenu(Menu menu, String accessToken) {int result = 0;// 拼装创建菜单的urlString url = MENU_CREATE_RUL.replace("ACCESS_TOKEN", accessToken);// 将菜单对象转换成json字符串String jsonMenu = JSON.toJSON(menu).toString();// 调用接口创建菜单JSONObject jsonObject = httpsRequest(url, "POST", jsonMenu);if (null != jsonObject) {if (0 != jsonObject.getInteger("errcode")) {result = jsonObject.getInteger("errcode");System.out.println("创建菜单失败 errcode:{} errmsg:{}" + jsonObject.getInteger("errcode") + jsonObject.getString("errmsg"));}}return result;}}

3.自定义菜单栏

@Testpublic void t() throws Exception {JSONObject accessToken = GetReqUtil.getAccess_token();MessageUtil.createMenu(MessageUtil.getMenu(), accessToken.getString("access_token"));}

public static JSONObject getAccess_token() {String url = "https://sz.api./cgi-bin/token";Map<String,Object> paramMap = new HashMap<>();paramMap.put("appid", "微信公众号的appid");paramMap.put("secret", "微信公众号的secret");paramMap.put("grant_type", "client_credential");String result2 = HttpRequest.get(url).charset(CharsetUtil.CHARSET_GBK).header(Header.USER_AGENT, "Hutool http")//头信息,多个头信息多次调用此方法即可.form(paramMap)//表单内容.timeout(20000)//超时,毫秒.execute().body();JSONObject jsonObject = JSONObject.parseObject(result2); //字符串转Mapreturn jsonObject;}

1.自定义菜单栏示例图:
2.点击自定义菜单栏回复图文

//消息类型 -- 事件(event)if (MessageUtil.REQ_MESSAGE_TYPE_EVENT.equals(requestMap.get("msgType"))) {if (MessageUtil.KEY.equals(requestMap.get("eventKey"))) {String openid = requestMap.get("fromUserName"); //用户openidString mpid = requestMap.get("toUserName"); //公众号原始ID//对图文消息NewsMessage newmsg = new NewsMessage();newmsg.setToUserName(openid);newmsg.setFromUserName(mpid);newmsg.setCreateTime(new Date().getTime());newmsg.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_NEWS);List<Article> articleList = new ArrayList<>();Article article = new Article();if (MessageUtil.INDUSTRY_TRENDS.equals(requestMap.get("eventKey"))) {//行业动态article.setTitle("标题");article.setDescription("描述");article.setPicUrl("图片URL, 可以把图片保存到微信公众号里的素材库, 然后使用图片的路径, 或者使用绝对路径");article.setUrl("链接URL");}articleList.add(article);// 设置图文消息个数newmsg.setArticleCount(articleList.size());// 设置图文消息包含的图文集合newmsg.setArticles(articleList);String msgrsp = MessageUtil.newsMessageToXml(newmsg);out.print(msgrsp);out.close();}}

NewMessage

public class NewsMessage extends BaseMessage {/*** 图文消息个数,限制为10条以内*/private Integer ArticleCount;/*** 多条图文消息信息,默认第一个item为大图*/private List<Article> Articles;public Integer getArticleCount() {return ArticleCount;}public NewsMessage setArticleCount(Integer articleCount) {ArticleCount = articleCount;return this;}public List<Article> getArticles() {return Articles;}public NewsMessage setArticles(List<Article> articles) {Articles = articles;return this;}

Article

@Datapublic class Article {/*** 图文消息描述*/private String Description;/*** 图片链接,支持JPG、PNG格式,<br>* 较好的效果为大图640*320,小图80*80*/private String PicUrl;/*** 图文消息名称*/private String Title;/*** 点击图文消息跳转链接*/private String Url;}

回复图文示例图:

微信现在不支持默认回复大图了, 如果需要大图得展示2条数据-> 一条文字, 一张图片

4.关键字回复

//消息类型 -- 文本(text)if (MessageUtil.REQ_MESSAGE_TYPE_TEXT.equals(requestMap.get("msgType"))) {//自定义文本if ("资讯".equals(requestMap.get("content"))) {StringBuilder stringBuilder = new StringBuilder();stringBuilder.append("XXXX年9月)" + "\n");stringBuilder.append("链接:XXXXX" + "\n");//可以让文字变蓝, 用户点击一下蓝色,会自己打出提取码, 然后容易拷贝stringBuilder.append("提取码:<a href=\"weixin://bizmsgmenu?msgmenuid=1&msgmenucontent=9tdy\">9tdy</a>" + "\n");String openid = requestMap.get("fromUserName"); //用户openidString mpid = requestMap.get("toUserName"); //公众号原始ID//普通文本消息BaseMessage txtmsg = new BaseMessage();txtmsg.setToUserName(openid);txtmsg.setFromUserName(mpid);txtmsg.setCreateTime(new Date().getTime());txtmsg.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);txtmsg.setContent(stringBuilder.toString());String msgrsp = MessageUtil.textMessageToXml(txtmsg);out.print(msgrsp);out.close();}}

示例图:

5.回复2条消息(1文字, 1图片)

示例图:

微信限制我们每次只能给用户被动回复一条消息, 所以回复2条只能使用客服推送这个功能

1.客服推送文字public static void processAppletTextMessage(Map<String, String> requestMap) {String openid = requestMap.get("fromUserName"); //用户openidJSONObject accessToken = GetReqUtil.getAccess_token();JSONObject jsonObject = new JSONObject();JSONObject jsonObject2 = new JSONObject();jsonObject2.put("content", "请联系工作人员进入小程序体验");jsonObject.put("touser", openid);jsonObject.put("msgtype", "text");jsonObject.put("text", jsonObject2);HttpUtil.post("https://sz.api./cgi-bin/message/custom/send?access_token=" + accessToken.getString("access_token"), jsonObject.toString());}2.回复图片信息public static String processAppletPictureMessage(Map<String, String> requestMap) {String openid = requestMap.get("fromUserName"); //用户openidString mpid = requestMap.get("toUserName"); //公众号原始IDImageMessage imageMsg = new ImageMessage();Image image = new Image();image.setMediaId("上传图片到微信服务器, 获取MediaId, 下面有");//普通文本消息imageMsg.setToUserName(openid);imageMsg.setFromUserName(mpid);imageMsg.setCreateTime(new Date().getTime());imageMsg.setMsgType(MessageUtil.REQ_MESSAGE_TYPE_IMAGE);imageMsg.setImage(image);return MessageUtil.imageMessageToXml(imageMsg);}

ImageMessage

@Datapublic class ImageMessage extends BaseMessage{private Image Image;}

把图片上传到微信素材库(永久上传)

@RunWith(SpringRunner.class)@SpringBootTest(classes = Application.class)@Testpublic void t2() throws Exception {JSONObject accessToken = GetReqUtil.getAccess_token();System.out.println("accessToken = " + accessToken.getString("access_token"));JSONObject jsonObject = GetReqUtil.addMaterialEver("C:\\Users\\Jaime\\Desktop\\工作人员.jpg", "image", accessToken.getString("access_token"));boolean b=jsonObject.containsKey("media_id");if (b==true) {String media_id=jsonObject.getString("media_id");System.out.println("jsonObject = " + jsonObject);System.out.println("media_id:"+media_id);}}

addMaterialEver

/*** 上传其他永久素材(图片素材的上限为5000,其他类型为1000)** @return* @throws Exception*/public static JSONObject addMaterialEver(String fileurl, String type, String token) {try {File file = new File(fileurl);//上传素材String path = "https://api./cgi-bin/material/add_material?access_token=" + token + "&type=" + type;String result = connectHttpsByPost(path, null, file);result = result.replaceAll("[\\\\]", "");JSONObject resultJSON = JSONObject.parseObject(result);if (resultJSON != null) {if (resultJSON.get("media_id") != null) {System.out.println("true");return resultJSON;} else {System.out.println("false");}}return null;} catch (Exception e) {e.printStackTrace();}return null;}public static String connectHttpsByPost(String path, String KK, File file) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException {URL urlObj = new URL(path);//连接HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();String result = null;con.setDoInput(true);con.setDoOutput(true);con.setUseCaches(false); // post方式不能使用缓存// 设置请求头信息con.setRequestProperty("Connection", "Keep-Alive");con.setRequestProperty("Charset", "UTF-8");// 设置边界String BOUNDARY = "----------" + System.currentTimeMillis();con.setRequestProperty("Content-Type","multipart/form-data; boundary="+ BOUNDARY);// 请求正文信息// 第一部分:StringBuilder sb = new StringBuilder();sb.append("--"); // 必须多两道线sb.append(BOUNDARY);sb.append("\r\n");sb.append("Content-Disposition: form-data;name=\"media\";filelength=\"" + file.length() + "\";filename=\""+ file.getName() + "\"\r\n");sb.append("Content-Type:application/octet-stream\r\n\r\n");byte[] head = sb.toString().getBytes("utf-8");// 获得输出流OutputStream out = new DataOutputStream(con.getOutputStream());// 输出表头out.write(head);// 文件正文部分// 把文件已流文件的方式 推入到url中DataInputStream in = new DataInputStream(new FileInputStream(file));int bytes = 0;byte[] bufferOut = new byte[1024];while ((bytes = in.read(bufferOut)) != -1) {out.write(bufferOut, 0, bytes);}in.close();// 结尾部分byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线out.write(foot);out.flush();out.close();StringBuffer buffer = new StringBuffer();BufferedReader reader = null;try {// 定义BufferedReader输入流来读取URL的响应reader = new BufferedReader(new InputStreamReader(con.getInputStream()));String line = null;while ((line = reader.readLine()) != null) {buffer.append(line);}if (result == null) {result = buffer.toString();}} catch (IOException e) {} finally {if (reader != null) {reader.close();}}return result;}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。