1、controller代码

@Controller
@RequestMapping("/wechat/platform")
public class WechatController extends AbstractController {// get请求,用于微信公众号配置url时验证@ResponseBody@GetMapping("test")public String test(String signature, String timestamp, String nonce, String echostr) {// 验签boolean bool = WechatUtils.checkSign(signature, timestamp, nonce);return bool ? echostr : null;}// post请求,公众号有聊天,扫码等事件时推送相关内容@ResponseBody@PostMapping("test")public String test(HttpServletRequest request) throws Exception {// 解密微信推送的消息Map<String, String> map = WechatUtils.decryptWxMsg2Map(request);// 用户openid和本次推送的消息类型String openid = request.getParameter("openid"), msgType = map.get("MsgType");if ("text".equals(msgType)) { // 文本消息// 做相应处理} else if ("event".equals(msgType)) { // 事件// event 事件类型,key 事件中的值String event = map.get("Event"), key = map.get("EventKey");// 玩家扫码绑定留言if ("SCAN".equalsIgnoreCase(event)) {} else if ("CLICK".equalsIgnoreCase(event)) {}}// 如果想返回自定义内容 return WechatUtils.encryptWxMsg2Xml(openid, platformId, "xxxxxx");// 不需要返回自定义内容或者五秒内业务处理不完,返回success,否则公众号提示异常return "success";}// 生成二维码,用于扫码登录@ResponseBody@RequestMapping(value = "makeCode")public R makeCode(HttpServletRequest request) throws Exception {String state = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();// java延时队列,多服务时,可存储redisBusinessDelayQueue instance = BusinessDelayQueue.getInstance();// 状态:false、未扫码,null、码失效,其他、扫码成功PublicTask task = new PublicTask("wx_" + state, "false");long expire = System.currentTimeMillis() + 300000;DelayTask<?> delay = new DelayTask<>(expire, task);instance.put(delay);return R.ok().put("url", String.format(wxConfig.getWxQrcode(), state)).put("state", state);}// 轮询扫码状态,最好使用websocket主动推送@ResponseBody@PostMapping(value = "checkState")public R checkState(String state) {PublicTask task = new PublicTask("wx_" + state, null);String value = task.getValue(String.class, false);if (value == null) {return R.error(-1, "二维码已失效").put(SysLogUtils.SYSLOG_NOT_SAVE, true);}if ("false".equals(value)) {return R.error(-2, "未扫码登录").put(SysLogUtils.SYSLOG_NOT_SAVE, true);}// info自定义的信息,比如user信息String info = task.getValue(String.class, true);return r;}// 用户扫码后微信端调用@RequestMapping(value = "openid")public String openid(String code, String state, Model model, HttpServletRequest request) throws IOException {// 获取openidString resp = HttpTookit.doGet(String.format(wxConfig.getWxOpenid(), code), null);String openid = JSON.parseObject(resp).getString("openid");// 获取用户信息,进行业务处理JSONObject user = WechatUtils.userInfo(openid);return "xxx";}// 模板消息推送public void pushMessage(String str, Integer type, String ext) {// 构造固定格式mapMap<String, Object> data = new HashMap<>(), map = new HashMap<>(), first = new HashMap<>(),k1 = new HashMap<>(), k2 = new HashMap<>(), k3 = new HashMap<>(), k4 = new HashMap<>(),remark = new HashMap<>();data.put("touser", openid);map.put("first", first);map.put("keyword1", k1);map.put("keyword2", k2);map.put("keyword3", k3);map.put("keyword4", k4);map.put("remark", remark);first.put("color", "#159815");k1.put("color", "#003AFF");k2.put("color", "#FF0066");k3.put("color", "#003AFF");k4.put("color", "#003AFF");remark.put("color", "#159815");data.put("template_id", "模板ID");data.put("data", map);WechatUtils.pushMessage(data);}
}

2、WechatUtils工具类

public class WechatUtils {public static String access_token = null;private static WXBizMsgCrypt crypt = null;static {try {// 微信消息解密器crypt = new WXBizMsgCrypt(wxConfig.getToken(), wxConfig.getAesKey(), wxConfig.getAppid());} catch (AesException e) {}}// 获取全局access_tokenpublic static void getAccessToken() {// wxConfig.getAccessToken():单独的微信服务器,提供全局access_tokenString format = String.format(wxConfig.getAccessToken(), access_token);access_token = HttpTookit.doGet(format, null);}// 获取用户信息public static void userInfo(String openid) {String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s";// 获取用户信息String info = HttpTookit.doGet(String.format(url, access_token, openid), null);}// 微信公众号配置url时的验签public static boolean checkSign(String signature, String timestamp, String nonce) {String arrs[] = { "微信公众号的token", timestamp, nonce };Arrays.sort(arrs);StringBuffer sb = new StringBuffer();for (String str : arrs) {sb.append(str);}String s= Sha1Util.encode(sb.toString());return s.equals(signature);}// 推送模板消息public static void pushMessage(Map<String, Object> data) throws Exception {String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s";String resp = HttpTookit.sendHttpPost(String.format(url, access_token), JSON.toJSONString(data));}// 对给微信公众号返回的消息加密public static String encryptWxMsg2Xml(String toOpenid, String fromOpenid, String content) throws Exception {String xml = "<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName>"+ "<CreateTime>%s</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[%s]]></Content></xml>";String createTime = Long.toString(System.currentTimeMillis() / 1000), nonce = SerialNumUtil.randam(10);// 明文消息,用于非安全模式// return String.format(xml, toOpenid, fromOpenid, createTime, content);// 加密消息,安全模式return crypt.encryptMsg(String.format(xml, toOpenid, fromOpenid, createTime, content), createTime, nonce);}// 解密微信公众号推送的消息public static Map<String, String> decryptWxMsg2Map(HttpServletRequest request) throws Exception {request.setCharacterEncoding("UTF-8");StringBuilder sb = new StringBuilder();// 获取服务器发送过来的信息,因为不是参数,得用输入流读取try (BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream(), "utf-8"))) {String line = null;while ((line = reader.readLine()) != null) {sb.append(line);}} catch (Exception e) {}String s= request.getParameter("msg_signature"), timeStamp = request.getParameter("timestamp"),nonce = request.getParameter("nonce");System.out.println("用户发送过来信息解密前:" + sb);String decryptMsg = crypt.decryptMsg(s, timeStamp, nonce, sb.toString());System.out.println("用户发送过来信息解密后:" + decryptMsg);// xml转mapreturn xmlToMap(decryptMsg);}// xml转mappublic static Map<String, String> xmlToMap(String strXML) throws Exception {Map<String, String> data = new HashMap<String, String>();DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();try (InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"))) {Document doc = documentBuilder.parse(stream);doc.getDocumentElement().normalize();NodeList nodeList = doc.getDocumentElement().getChildNodes();for (int idx = 0; idx < nodeList.getLength(); ++idx) {Node node = nodeList.item(idx);if (node.getNodeType() == Node.ELEMENT_NODE) {org.w3c.dom.Element element = (org.w3c.dom.Element) node;data.put(element.getNodeName(), element.getTextContent());}}}return data;}// map转xmlpublic static String mapToXml(String toOpenid, String fromOpenid, String timestamp, String content) {String xml = "<xml>" + "<ToUserName><![CDATA[%s]]></ToUserName>"+ "<FromUserName><![CDATA[%s}]]></FromUserName>" + "<CreateTime>%s</CreateTime>"+ "<MsgType><![CDATA[text]]></MsgType>" + "<Content><![CDATA[%s]]></Content>"+ "<MsgId>1234567890123456</MsgId> " + "</xml>";return String.format(xml, toOpenid, fromOpenid, timestamp, content);}}

3、Java延时队列相关类

public class BusinessDelayQueue {private final static int DEFAULT_THREAD_NUM = 10;private ExecutorService executor;public DelayQueue<DelayTask<?>> delayQueue;private Thread daemonThread;private static BusinessDelayQueue instance = new BusinessDelayQueue();private BusinessDelayQueue() {executor = Executors.newFixedThreadPool(DEFAULT_THREAD_NUM);delayQueue = new DelayQueue<>();init();}public static BusinessDelayQueue getInstance() {return instance;}public void init() {daemonThread = new Thread(() -> {execute();});daemonThread.setName("DelayQueueMonitor");daemonThread.start();}private void execute() {while (true) {try {DelayTask<?> delayTask = delayQueue.take();if (delayTask != null) {Callable<Integer> task = delayTask.getTask();if (null == task) {continue;}// 提交到线程池执行taskexecutor.submit(task);}} catch (Exception e) {}}}// 添加public void put(DelayTask<?> delay) {if(delayQueue.contains(delay)) {delayQueue.remove(delay);}delayQueue.put(delay);}// 停止任务public boolean removeTask(DelayTask<?> delay) {return delayQueue.remove(delay);}}public class DelayTask<T extends Callable<Integer>> implements Delayed {private final long expire; // 到期时间private T task; // 数据public DelayTask(long expire, T task) {this.expire = expire;this.task = task;}@Overridepublic int compareTo(Delayed o) {long self = this.getDelay(TimeUnit.MILLISECONDS), other = o.getDelay(TimeUnit.MILLISECONDS);return self <= other ? -1 : 1;}@Overridepublic long getDelay(TimeUnit unit) {return unit.convert(this.expire - System.currentTimeMillis(), TimeUnit.MILLISECONDS);}public T getTask() {return task;}// 记得重写equals和hashcode
}public class PublicTask implements Callable<Integer> {private String key;private Object value;public PublicTask(String key, Object value) {this.key = key;this.value = value;}@Overridepublic Integer call() throws Exception {// 业务处理return null;}// 记得重写equals和hashcode
}

微信公众号开发相关功能相关推荐

  1. 『总结』微信公众号开发相关问题

    公众号问题列表 1. 软键盘遮住输入框的问题:ios键盘被挡住(fixed定位或者absolute定位) 方法1: <script> window.onload = function(){ ...

  2. python微信公众号开发音乐功能_python利用微信公众号实现报警功能

    python利用微信公众号实现报警功能 发布时间:2020-09-23 09:54:05 来源:脚本之家 阅读:84 作者:Python火火 微信公众号共有三种,服务号.订阅号.企业号.它们在获取Ac ...

  3. 微信公众号开发相关问题

    官方文档 开发者文档 在线接口调试工具 公众平台测试帐号 http://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t ...

  4. 微信公众号-开发相关信息了解

    最近想了解微信小程序开发流程,在知乎里面看到了这篇文章,供大家参考 作者:初雪 链接:https://www.zhihu.com/question/50907897/answer/128494332 ...

  5. 手把手教你如何微信公众号开发“翻译功能

    翻译,我想这个功能已经很常见了,而且很多地方都有实现了,另外,不只是翻译功能,还可以是语音翻译等等,这些都是可以实现的,所以,写这篇文章,主要是介绍如何将公开的接口进行实际的使用..授人以鱼不如授人以 ...

  6. springboot实战-微信公众号开发

    sell 基于springboot的微信公众号系统,旨在学习springboot以及微信公众号开发相关知识 包含: springboot:表单验证.统一异常处理.事物管理.restful Api开发 ...

  7. 公众号分享页面php,微信公众号网页分享功能开发的示例代码

    现在每天都可以看到很多微信分享的链接上面有网站或者商家的自定义的分享标题,和分享链接的描述及分享出去的图像,例如下面的分享出去的链接: 上面这个是微信的js-SDK页面分享给微信好友在聊天列表中显示的 ...

  8. mysql编写倒计时_微信公众号开发,实现倒计时的一个功能(纯代码)

    微信公众号开发,实现倒计时的一个功能(纯代码),请在,公众,订单,代码,时间 微信公众号开发,实现倒计时的一个功能(纯代码) 易采站长站,站长之家为您整理了微信公众号开发,实现倒计时的一个功能(纯代码 ...

  9. 微信公众号开发笔记(三):微信JSAPI支付功能开发

    很久之前做了微信支付,其中也趟过很多坑,现在有时间就做个自我梳理吧算是. 公众号开发的基本配置(不明白的可以参考https://blog.csdn.net/TOP__ONE/article/detai ...

最新文章

  1. Android点击图标重新启动问题
  2. 机器视觉:makefile编译调用Caffe框架的C++程序
  3. Django模型(一)
  4. fstab各项参数及ls-l 长格式各项信息
  5. 气死N个女孩子的图片
  6. matlab中将小数四舍五入,matlab 四舍五入 保留至指定小数(图)
  7. pymavlink 源码剖析(一)之XML文件的数据解析
  8. 搜狗浏览器收藏夹在哪_安卓Edge浏览器最新版42.0.2轻体验,整体优良但无特别惊喜...
  9. PyTorch: torch.optim 的6种优化器及优化算法介绍
  10. 浮动元素横排居中显示及浏览器兼容性处理
  11. 基于 Intel 的 Mac,如何使用机构恢复密钥的技巧
  12. linux端口被墙了 开通端口
  13. linux专业的打谱软件下载,MuseScore 3.1 发布,音乐制谱软件
  14. 2018华为软件精英挑战赛体会
  15. windows dhcp服务器使用脚本批量创建作用域
  16. LeetCode-Python-275. H指数 II
  17. 在html中什么是锚点
  18. 微信小程序座位预约,微信小程序实现订座位,餐厅座位预约小程序毕设作品
  19. 解决echart在tab中切换时显示不正确
  20. 【已解决】笔记本电脑连接wifi异常(无法连接到这个网络)

热门文章

  1. python连接sql server2008教程_Python连接SQL Server数据库
  2. 最速下降法 c 语言程序,工程優化方法中的“最速下降法”和“DFP擬牛頓法”的 C 語言實現...
  3. jmeter模拟mysql长连接_jmeter链接mysql数据库
  4. SDUT java 单词和字符鉴别器
  5. 调节阀卡塞的处理方法
  6. 数据结构实验一 —— 矩阵相乘算法
  7. Centos7镜像iso挂载配置本地yum源
  8. 杭电ACM1049题
  9. Win7系统下安装Python环境以及IDE开发环境(PyCharm)
  10. java计算机毕业设计vue开发一个简单音乐播放器源码+mysql数据库+系统+lw文档+部署