日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java实现微信公众号自动回复

發(fā)布時(shí)間:2023/12/10 java 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java实现微信公众号自动回复 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文最先發(fā)表于我的個(gè)人博客,CSDN為同步發(fā)布,如有需要,請?jiān)L問 腿短快跑的個(gè)人博客 獲取更多內(nèi)容

背景

最近準(zhǔn)備搭建自己的博客系統(tǒng),有些軟件或資料的下載鏈接放在網(wǎng)盤中,為了方便下載,同時(shí)可以將用戶導(dǎo)流到公眾號(hào)上,因此準(zhǔn)備用Java實(shí)現(xiàn)微信公眾號(hào)自動(dòng)回復(fù)的功能

準(zhǔn)備工作

  • 微信公眾號(hào)

首先當(dāng)然是需要注冊一個(gè)微信公眾號(hào),具體步驟就不在這里贅述了,注冊地址:微信公眾平臺(tái)

注冊完畢后需要完成認(rèn)證操作

代碼

依賴引入,主要為xml相關(guān)依賴, 因?yàn)槲⑿殴娞?hào)采用的xml消息格式進(jìn)行交互

<dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.6.1</version> </dependency> <dependency><groupId>com.thoughtworks.xstream</groupId><artifactId>xstream</artifactId><version>1.4.19</version> </dependency>

自動(dòng)回復(fù)內(nèi)容一共需要兩個(gè)接口(兩個(gè)接口路由完全一致,一個(gè)為GET請求,一個(gè)為POST請求)

  • 微信公眾號(hào)認(rèn)證接口

此接口用于微信公眾號(hào)后臺(tái)服務(wù)器認(rèn)證使用,GET請求

/*** 微信校驗(yàn)** @param signature* @param timestamp* @param nonce* @param echostr* @param response*/@GetMapping("callback")public void callback(String signature, String timestamp, String nonce, String echostr, HttpServletResponse response) {PrintWriter out = null;log.info("微信校驗(yàn)消息,signature:{},timestamp:{},nonce:{},echostr:{}", signature, timestamp, nonce, echostr);List<WechatConfigPO> configPOList = wechatConfigDao.selectAll();try {out = response.getWriter();out.write(echostr);} catch (Throwable e) {log.error("微信校驗(yàn)失敗", e);} finally {if (out != null) {out.close();}}}
  • 消息接收接口

此接口用于接收公眾號(hào)消息回調(diào),POST請求

/*** 微信消息回調(diào)** @param request* @param response*/@PostMapping("callback")public void callback(HttpServletRequest request, HttpServletResponse response) {PrintWriter out = null;try {String respMessage = wechatService.callback(request);if (StringUtils.isBlank(respMessage)) {log.info("不回復(fù)消息");return;}response.setCharacterEncoding("UTF-8");out = response.getWriter();out.write(respMessage);} catch (Throwable e) {log.error("微信發(fā)送消息失敗", e);} finally {if (out != null) {out.close();}}}

消息回復(fù)service

/*** @author C.W* @date 2022/5/18 7:32* @desc 微信*/ @Slf4j @Service public class WechatService {@Autowiredprivate TextReplyService textReplyService;/*** 微信回復(fù)** @param request* @return* @throws UnsupportedEncodingException*/public String callback(HttpServletRequest request) throws UnsupportedEncodingException {request.setCharacterEncoding("UTF-8");try {Map<String, String> requestMap = WechatMessageUtils.parseXml(request);log.info("微信接收到消息:{}", GsonUtils.toJson(requestMap));// 消息類型String msgType = requestMap.get("MsgType");// 處理其他消息,暫時(shí)不做回復(fù)switch (msgType) {case WechatMsgTypeConstant.MESSAGE_TYPE_TEXT:// 文本消息處理return textReplyService.reply(requestMap);default:return textReplyService.reply(requestMap);}} catch (Throwable e) {log.error("回復(fù)消息錯(cuò)誤", e);}// 不做回復(fù)return null;}}

文本回復(fù)service

/*** @author C.W* @date 2022/5/18 9:57* @desc 文本回復(fù)*/ @Service public class TextReplyService {private static final String FROM_USER_NAME = "FromUserName";private static final String TO_USER_NAME = "ToUserName";private static final String CONTENT = "Content";@Autowiredprivate WechatKeywordDao wechatKeywordDao;@Autowiredprivate WechatMsgRecordDao wechatMsgRecordDao;/*** 自動(dòng)回復(fù)文本內(nèi)容** @param requestMap* @return*/public String reply(Map<String, String> requestMap) {String wechatId = requestMap.get(FROM_USER_NAME);String gongzhonghaoId = requestMap.get(TO_USER_NAME);TextMessage textMessage = WechatMessageUtils.getDefaultTextMessage(wechatId, gongzhonghaoId);String content = requestMap.get(CONTENT);if (content == null) {textMessage.setContent(WechatConstants.DEFAULT_MSG);} else {Example example = new Example(WechatKeywordPO.class);example.createCriteria().andEqualTo("wechatId", gongzhonghaoId).andEqualTo("keyword", content);List<WechatKeywordPO> keywordPOList = wechatKeywordDao.selectByExample(example);if (CollectionUtils.isEmpty(keywordPOList)) {textMessage.setContent(WechatConstants.DEFAULT_MSG);} else {textMessage.setContent(keywordPOList.get(0).getReplyContent());}}// 記錄消息記錄wechatMsgRecordDao.insertSelective(WechatMsgRecordPO.builder().fromUser(wechatId).wechatId(gongzhonghaoId).content(content).replyContent(textMessage.getContent()).build());return WechatMessageUtils.textMessageToXml(textMessage);}}

文本消息model

/*** @author C.W* @date 2021/11/26 22:21* @description 文本消息*/ @Data public class TextMessage extends BaseMessage {/*** 回復(fù)的消息內(nèi)容*/private String Content;}

基礎(chǔ)消息model

/*** @author C.W* @date 2021/11/26 22:20* @description 基礎(chǔ)消息響應(yīng)*/ @Data public class BaseMessage {/*** 接收方帳號(hào)(收到的OpenID)*/private String ToUserName;/*** 開發(fā)者微信號(hào)*/private String FromUserName;/*** 消息創(chuàng)建時(shí)間 (整型)*/private long CreateTime;/*** 消息類型*/private String MsgType;/*** 位0x0001被標(biāo)志時(shí),星標(biāo)剛收到的消息*/private int FuncFlag;}

消息工具

/*** @author C.W* @date 2022/5/18 7:55* @desc 微信消息*/ public class WechatMessageUtils {/*** 解析微信發(fā)來的請求(XML)** @param request* @return* @throws Exception*/public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {// 將解析結(jié)果存儲(chǔ)在HashMap中Map<String, String> map = new HashMap<>();// 從request中取得輸入流InputStream inputStream = request.getInputStream();try {// 讀取輸入流SAXReader reader = new SAXReader();Document document = reader.read(inputStream);// 得到xml根元素Element root = document.getRootElement();// 得到根元素的所有子節(jié)點(diǎn)List<Element> elementList = root.elements();// 遍歷所有子節(jié)點(diǎn)for (Element e : elementList) {map.put(e.getName(), e.getText());}} finally {// 釋放資源if (inputStream != null) {inputStream.close();}}return map;}/*** 文本消息對象轉(zhuǎn)換成xml** @param textMessage 文本消息對象* @return xml*/public static String textMessageToXml(TextMessage textMessage) {XSTREAM.alias("xml", textMessage.getClass());return XSTREAM.toXML(textMessage);}/*** 音樂消息對象轉(zhuǎn)換成xml** @param musicMessage 音樂消息對象* @return xml*/public static String musicMessageToXml(MusicMessage musicMessage) {XSTREAM.alias("xml", musicMessage.getClass());return XSTREAM.toXML(musicMessage);}/*** 圖文消息對象轉(zhuǎn)換成xml** @param newsMessage 圖文消息對象* @return xml*/public static String newsMessageToXml(NewsMessage newsMessage) {XSTREAM.alias("xml", newsMessage.getClass());XSTREAM.alias("item", Article.class);return XSTREAM.toXML(newsMessage);}/*** 擴(kuò)展xstream,使其支持CDATA塊*/private static final XStream XSTREAM = new XStream(new XppDriver() {@Overridepublic HierarchicalStreamWriter createWriter(Writer out) {return new PrettyPrintWriter(out) {// 對所有xml節(jié)點(diǎn)的轉(zhuǎn)換都增加CDATA標(biāo)記final boolean cdata = true;@Overrideprotected void writeText(QuickWriter writer, String text) {if (cdata) {writer.write("<![CDATA[");writer.write(text);writer.write("]]>");} else {writer.write(text);}}};}});/*** 獲取默認(rèn)文本消息** @param receiver 接收人* @param officialWxid 官方微信id* @return 文本消息*/public static TextMessage getDefaultTextMessage(String receiver, String officialWxid) {TextMessage textMessage = new TextMessage();textMessage.setToUserName(receiver);textMessage.setFromUserName(officialWxid);textMessage.setCreateTime(System.currentTimeMillis());textMessage.setMsgType(WechatMsgTypeConstant.MESSAGE_TYPE_TEXT);textMessage.setFuncFlag(0);return textMessage;}}

消息類型枚舉

/*** @author C.W* @date 2022/5/18 8:00* @desc 微信消息類型*/ public class WechatMsgTypeConstant {/*** 文本消息*/public static final String MESSAGE_TYPE_TEXT = "text";}

其他內(nèi)容為一些數(shù)據(jù)庫相關(guān)操作,此處不再列出,僅為:查詢關(guān)鍵詞及其回復(fù)內(nèi)容存儲(chǔ)消息記錄

公眾號(hào)配置

  • 服務(wù)器配置

公眾號(hào)后臺(tái) -> 設(shè)置與開發(fā) -> 基本配置 -> 服務(wù)器配置

  • 填寫服務(wù)器地址

填寫你的服務(wù)器回調(diào)接口地址(需要為公網(wǎng)地址,否則微信無法調(diào)通)

  • 生成你的令牌Token

Token 需要記住,一般在微信驗(yàn)證接口處會(huì)校驗(yàn)相關(guān)信息是否是自己的公眾號(hào)

驗(yàn)證方法

/*** @author C.W* @date 2021/11/26 21:59* @description 微信工具*/ @Slf4j public class WechatUtils {private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5','6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};public static boolean checkSignature(String signature, String timestamp, String nonce, String token) {String[] str = new String[]{token, timestamp, nonce};//排序Arrays.sort(str);//拼接字符串StringBuffer buffer = new StringBuffer();for (int i = 0; i < str.length; i++) {buffer.append(str[i]);}//進(jìn)String temp = encode(buffer.toString());//與微信提供的signature進(jìn)行匹對return signature.equals(temp);}private static String getFormattedText(byte[] bytes) {int len = bytes.length;StringBuilder buf = new StringBuilder(len * 2);for (int j = 0; j < len; j++) {buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);buf.append(HEX_DIGITS[bytes[j] & 0x0f]);}return buf.toString();}public static String encode(String str) {if (str == null) {return null;}try {MessageDigest messageDigest = MessageDigest.getInstance("SHA1");messageDigest.update(str.getBytes());return getFormattedText(messageDigest.digest());} catch (Exception e) {throw new RuntimeException(e);}}}
  • 驗(yàn)證公眾號(hào)自動(dòng)回復(fù)是否正確

可以關(guān)注公眾號(hào) 抓娃程序員,發(fā)送關(guān)鍵詞:回復(fù) 體驗(yàn)效果

總結(jié)

以上是生活随笔為你收集整理的Java实现微信公众号自动回复的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。