Spring + Fastweixin 微信开发
这篇文章转自《http://www.qtdebug.com/spring-weixin/》
微信有两种模式,编辑模式和开发者模式,有些功能是互斥的,不可以同时使用,微信开发需要在开发者模式下进行(开发者模式下仍然可以去微信的网页上群发消息)。下面介绍的功能能满足大部分的需求,响应文本消息,图文消息,创建菜单,响应菜单消息等。
我们给微信提供服务有两种消息模式,被动和主动
- 被动: 例如用户输入文本,点击菜单,微信服务器会访问我们的 Web 服务对应的 URL,我们返回对应的消息给微信服务器
- 主动: 例如创建菜单,群发消息,这种模式需要我们主动去触发,给微信服务器发送消息,可以是执行某个定时任务触发,或者我们访问某个 URL 然后在其响应的代码里触发
几个关键点
- 微信服务器和我们的服务器绑定验证时使用 GET 发送一个带有
echostr
参数的请求 - 其他消息使用的是 POST,常用的消息有
- 事件消息 event: subscribe, unsubscribe, location 等
- 文本消息 text: 可以回复文本,链接,图文
- 点击菜单回复的 click
- 点击菜单跳转为 view
- 微信服务器访问我们的服务器的 URL 只有一个,就是在配置页中配置的 URL
- 使用 app_id + app_secret 从微信服务器获取 access_token,有效时间是 7200 秒
- 微信的接口:用于我们主动的从微信服务器获取信息或者主动的向微信服务器写入信息
准备外网能访问的域名
- 使用 ngrok.cc 让本地服务能在外网访问,这样微信服务器才能访问到我们的 Web 服务器
准备公众号
- 访问 https://mp.weixin.qq.com 注册开发者账号
- 登陆后到最下面
开发 > 基本配置
中启用开发者模式,并点击修改配置
配置我们自己给微信提供服务的 Web 地址、Token 等,然后使用appID
和appsecret
就可以进行开发了- 如果我们申请的是
个人订阅号
,很多功能接口都没有,例如自定义菜单都没有,为了使用所有的功能进行开发练习,可以使用微信提供的公众平台测试帐号
:开发 > 开发者工具 > 公众平台测试帐号 > 进入
,就可以看到appID
和appsecret
,也需要在这里配置给微信提供服务的 Web 地址,Token 等,然后在页面中部找到请用微信扫描关注测试公众号
,扫描关注即可 - 查看公众号接口权限说明:
开发 > 开发者工具 > 开发者文档 > 进入 > 公众号接口权限说明
个人订阅号
是不能进行认证的Gradle 依赖
1compile("com.github.sd4324530:fastweixin:1.3.11")Fastweixin 的 git: https://git.oschina.net/pyinjava/fastweixin
给微信提供服务的 Controller
1public class WeixinController extends WeixinControllerSupport消息响应
在 WeixinController 中重载下面几个函数
响应订阅消息
1protected BaseMsg handleSubscribe(BaseEvent event)响应文本消息
1protected BaseMsg handleTextMsg(TextReqMsg msg)响应点击菜单消息
1protected BaseMsg handleMenuClickEvent(MenuEvent event)
创建消息
创建文本消息
1new TextMsg("你好: <a href=\"http://www.baidu.com\">百度</a>");创建图文消息(单图文,多图文都可以)
1234String picUrl = "http://image.17car.com.cn/image/20120810/20120810092133_13289.jpg"; // 消息中显示的图片String url = "http://news.17car.com.cn/saishi/20120810/336283.html"; // 点击消息后跳转的网页的地址String description = "700 马力道路赛车 DDMWorks 打造最强 Atom";NewsMsg msg = new NewsMsg(Arrays.asList(new Article("Atom", description, picUrl, url), new Article("Atom", description, picUrl, url)));
创建菜单
创建菜单
- 微信不会访问这个URL,需要我们自己访问创建菜单的 URL,然后才能向微信发送创建菜单信息。
- 微信只能保证菜单 24 小时之类生效,想要马上看到菜单效果,先取消关注,然后再次关注就可以了
CLICK
类型的菜单会发送消息到我们的服务器,handleMenuClickEvent() 进行响应,根据 key 来判断是哪个菜单被点击VIEW
类型的菜单不回发送消息到我们的服务器,而是直接跳转到对应的 URL- 菜单分一级菜单和二级菜单
- 最多有 3 个一级菜单,5 个二级菜单
- 一级菜单最多 4 个汉字,二级菜单最多 7 个汉字
123456789101112131415161718192021222324252627282930313233343536373839@GetMapping("/create-menu")@ResponseBodypublic String createMenu() {// 准备一级主菜单MenuButton main1 = new MenuButton();main1.setType(MenuType.CLICK); // 可点击的菜单main1.setKey("main1");main1.setName("主菜单一");MenuButton main2 = new MenuButton();main2.setType(MenuType.VIEW); // 链接的菜单,点击后跳转到对应的 URLmain2.setName("主菜单二");main2.setUrl("http://www.baidu.com");MenuButton main3 = new MenuButton();main3.setType(MenuType.CLICK);main3.setName("真题");// 带有子菜单MenuButton sub1 = new MenuButton();sub1.setType(MenuType.CLICK); // 带有子菜单sub1.setName("2016 语文");sub1.setKey("sub1");MenuButton sub2 = new MenuButton();sub2.setType(MenuType.CLICK);sub2.setName("2016 数学");sub2.setKey("sub2");main3.setSubButton(Arrays.asList(sub1, sub2));Menu menu = new Menu();menu.setButton(Arrays.asList(main1, main2, main3));//创建菜单ApiConfig config = new ApiConfig(APP_ID, APP_SECRET);MenuAPI menuAPI = new MenuAPI(config);ResultType resultType = menuAPI.createMenu(menu);return resultType.toString();}使用 Json 字符串创建菜单
上面的程序创建菜单太麻烦了,可以使用 Json 字符串,然后反序列化为菜单对象,下面使用 Jackson 来实现。
Jackson 依赖:
compile("com.fasterxml.jackson.core:jackson-databind:2.7.4")
菜单的 Json 字符串可以放在文件,数据库中等,方便修改,而且比使用对象的方式更直观,例如下面这样:
1234567891011121314151617181920212223{"button": [{"type": "CLICK","name": "主菜单一","key": "main1"}, {"type": "VIEW","name": "主菜单二","url": "http://www.baidu.com"}, {"type": "CLICK","name": "真题","subButton": [{"type": "CLICK","name": "2016 语文","key": "sub1"}, {"type": "CLICK","name": "2016 数学","key": "sub2"}]}]}1234567891011121314151617181920212223242526272829303132333435@GetMapping("/create-menu")@ResponseBodypublic String createMenu() throws Exception {String json = "{\n" +" \"button\": [{\n" +" \"type\": \"CLICK\",\n" +" \"name\": \"今日歌曲\",\n" +" \"key\": \"V1001_TODAY_MUSIC\"\n" +" }, {\n" +" \"name\": \"菜单\",\n" +" \"subButton\": [{\n" +" \"type\": \"VIEW\",\n" +" \"name\": \"搜索\",\n" +" \"url\": \"http://www.soso.com/\"\n" +" }, {\n" +" \"type\": \"VIEW\",\n" +" \"name\": \"视频\",\n" +" \"url\": \"http://v.qq.com/\"\n" +" }, {\n" +" \"type\": \"CLICK\",\n" +" \"name\": \"赞一下我们\",\n" +" \"key\": \"V1001_GOOD\"\n" +" }]\n" +" }]\n" +"}";ObjectMapper mapper = new ObjectMapper();Menu menu = mapper.readValue(json, Menu.class);//创建菜单ApiConfig config = new ApiConfig(APP_ID, APP_SECRET);MenuAPI menuAPI = new MenuAPI(config);ResultType resultType = menuAPI.createMenu(menu);return resultType.toString();}示例程序
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122package com.xtuer.controller;import com.github.sd4324530.fastweixin.api.MenuAPI;import com.github.sd4324530.fastweixin.api.config.ApiConfig;import com.github.sd4324530.fastweixin.api.entity.Menu;import com.github.sd4324530.fastweixin.api.entity.MenuButton;import com.github.sd4324530.fastweixin.api.enums.MenuType;import com.github.sd4324530.fastweixin.api.enums.ResultType;import com.github.sd4324530.fastweixin.message.Article;import com.github.sd4324530.fastweixin.message.BaseMsg;import com.github.sd4324530.fastweixin.message.NewsMsg;import com.github.sd4324530.fastweixin.message.TextMsg;import com.github.sd4324530.fastweixin.message.req.MenuEvent;import com.github.sd4324530.fastweixin.message.req.TextReqMsg;import com.github.sd4324530.fastweixin.servlet.WeixinControllerSupport;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.RestController;import java.util.Arrays;@RestController@RequestMapping("/weixin")public class WeixinController extends WeixinControllerSupport {private static final Logger LOG = LoggerFactory.getLogger(WeixinController.class);private static final String TOKEN = "xxxxxx"; // 你的 tokenprivate static final String APP_ID = "yyyyyy"; // 你的 appIDprivate static final String APP_SECRET = "zzzzzz"; // 你的 appsecret// 重写父类方法,处理对应的微信消息@Overrideprotected BaseMsg handleTextMsg(TextReqMsg msg) {String content = msg.getContent(); // content 是用户输入的信息switch (content.toUpperCase()) {case "URL":// 消息中有链接return new TextMsg("你好: <a href=\"http://www.baidu.com\">百度</a>");case "ATOM":// 图文消息String picUrl = "http://image.17car.com.cn/image/20120810/20120810092133_13289.jpg"; // 消息中显示的图片String url = "http://news.17car.com.cn/saishi/20120810/336283.html"; // 点击消息后跳转的网页的地址String description = "700 马力道路赛车 DDMWorks 打造最强 Atom";return new NewsMsg(Arrays.asList(new Article("Atom", description, picUrl, url), new Article("Atom", description, picUrl, url)));default:return new TextMsg("不识别的命令, 您输入的内容是: " + content);}}@Overrideprotected BaseMsg handleMenuClickEvent(MenuEvent event) {String key = event.getEventKey();switch (key.toUpperCase()) {case "MAIN1":return new TextMsg("点击按钮");case "SUB1":return new TextMsg("2016 语文");case "SUB2":return new TextMsg("2016 数学");default:return new TextMsg("不识别的菜单命令");}}// 设置 TOKEN,用于绑定微信服务器@Overrideprotected String getToken() {return TOKEN;}// 获取 access token: http://localhost:8080/weixin/access-token@GetMapping("/access-token")@ResponseBodypublic String getAccessToken() {ApiConfig config = new ApiConfig(APP_ID, APP_SECRET);return config.getAccessToken();}// 创建菜单, 访问 http://localhost:8080/weixincreate-menu 就会把菜单信息发送给微信服务器@GetMapping("/create-menu")@ResponseBodypublic String createMenu() {// 准备一级主菜单MenuButton main1 = new MenuButton();main1.setType(MenuType.CLICK); // 可点击的菜单main1.setKey("main1");main1.setName("主菜单一");MenuButton main2 = new MenuButton();main2.setType(MenuType.VIEW); // 链接的菜单,点击后跳转到对应的 URLmain2.setName("主菜单二");main2.setUrl("http://www.baidu.com");MenuButton main3 = new MenuButton();main3.setType(MenuType.CLICK); // 带有子菜单main3.setName("真题");// 带有子菜单MenuButton sub1 = new MenuButton();sub1.setType(MenuType.CLICK);sub1.setName("2016 语文");sub1.setKey("sub1");MenuButton sub2 = new MenuButton();sub2.setType(MenuType.CLICK);sub2.setName("2016 数学");sub2.setKey("sub2");main3.setSubButton(Arrays.asList(sub1, sub2));Menu menu = new Menu();menu.setButton(Arrays.asList(main1, main2, main3));//创建菜单ApiConfig config = new ApiConfig(APP_ID, APP_SECRET);MenuAPI menuAPI = new MenuAPI(config);ResultType resultType = menuAPI.createMenu(menu);return resultType.toString();}}
- 如果我们申请的是
- 微信服务器和我们的服务器绑定验证时使用 GET 发送一个带有
Spring + Fastweixin 微信开发的更多相关文章
- 基于fastweixin的微信开发环境搭建(一)
由于公司业务需要,开发微信版本,才开始接触微信公众平台.在github折腾了几天,试过好几个微信sdk,最终选择fastweixin.个人觉得这个框架还是值得使用的,使用也简单.那么问题来了,很多人想 ...
- 分享 Java微信开发SDK
分享 Java微信开发SDK •发布于 4周前 •作者 朋也 •432 次浏览 •最后一次编辑是 2周前 •来自 分享 给大家分享两个java开发微信公众号的sdk jfinal-weixin ...
- spring boot + vue + element-ui全栈开发入门——spring boot后端开发
前言 本文讲解作为后端的spring boot项目开发流程,如果您还不会配置spring boot环境,就请点击<玩转spring boot——快速开始>,如果您对spring boot还 ...
- 微信开发(一)基于Wx-java的微信分享功能
最近在做微信服务号开发,简单总结一下,便于自己学习积累和分享给大家: 环境介绍: Spring+ Spring MVC +Mybatis 开发语言: JAVA 微信公众平台的开发中,微信只公布了一个基 ...
- 微信开发之如何使用开发工具--weixin-java-tools
一.前沿 微信公众平台由于没有提供针对语言的开发包,只公布了一个基于Http协议的接口和加解密的算法sdk,这样给微信公众号的开发者带来很多工作量,除了实现业务逻辑外,还需要自己处理底层的接口协议细节 ...
- SSM到Spring Boot-从零开发校园商铺平台
第1章 开发准备 本章包含课程介绍,同时讲解开发网站所需要准备的事情,并且带领大家从零开始搭建一个Maven Web. 1-1 课程导学 1-2 开发准备 第2章 项目设计和框架搭建 本章主要先带领大 ...
- 10个Spring Boot快速开发的项目,接私活利器(快速、高效)
本文为大家精选了 码云 上优秀的 Spring Boot 语言开源项目,涵盖了企业级系统框架.文件文档系统.秒杀系统.微服务化系统.后台管理系统等,希望能够给大家带来一点帮助:) 1.项目名称:分布式 ...
- 【Spring注解驱动开发】聊聊Spring注解驱动开发那些事儿!
写在前面 今天,面了一个工作5年的小伙伴,面试结果不理想啊!也不是我说,工作5年了,问多线程的知识:就只知道继承Thread类和实现Runnable接口!问Java集合,竟然说HashMap是线程安全 ...
- 【Spring注解驱动开发】组件注册-@ComponentScan-自动扫描组件&指定扫描规则
写在前面 在实际项目中,我们更多的是使用Spring的包扫描功能对项目中的包进行扫描,凡是在指定的包或子包中的类上标注了@Repository.@Service.@Controller.@Compon ...
随机推荐
- vim基础详解
目录: 什么是vim Vim能做什么 如何学习vim 如何用vim打开一个文件 Vim的三种模式 插入模式 命令模式 扩展命令模式 光标移动 在命令模式下 删除,复制,粘贴 扩展命令模式 可视化模式 ...
- JavaEE成长之路
前言 学习Java已经有一段时间了,在学习的过程中也走过了不少弯路. 写下这篇博文,主要是想记录下自己学习编程之路,以及反思自己在学习的时候出现的问题,下面也会给出我自认为学习JavaEE的路线,想要 ...
- 原型那些事 - JavaScript深入浅出(三)
前两次总结了JavaScript中的基本数据类型(值类型<引用类型>,引用类型<复杂值>)以及他们在内存中的存储,对内存空间有了一个简单的了解,以及第二次总结了this深入浅出 ...
- 关于搭建php电商环境时缺少fileinfo、数据库安装出错问题解决办法
今天以WSTMart电商系统为例讲解 搭建php电商环境缺少fileinfo.数据库安装出错问题找了很多方法都没能很好解决,该方法简单明了,容易操作 首先需要到开源中国中下载该系统源码,网址为:htt ...
- GitHub开源:升讯威微信营销系统(第三方微信平台)完整源代码
GitHub:https://github.com/iccb1013/Sheng.WeixinConstruction 升讯威微信营销系统开发实践系列升讯威微信营销系统开发实践:(1)功能设计与架构设 ...
- Markdown 编写规范
说明及目的 作为一个在博客园混迹了俩三年的人,一直在这里看别人的博客,现在准备开始写自己的博客,目的呢,就是一下几点吧: 项目过程中的历史经验教训积累记载,吃一堑长一智,不想在同一个坑掉进去好几次 学 ...
- [Java语言] 《struts2和spring MVC》的区别_动力节点
1.Struts2是类级别的拦截, 一个类对应一个request上下文,SpringMVC是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上Spr ...
- Webx项目的获取与验证
在JavaWeb环境配置后就可进行Webx实例项目的获取与研读了. 1.创建一个初始的Demo工程. 1)下载 Webx Maven 项目的目录结构Artifact插件. archetype-webx ...
- CSS图片垂直居中方法整理集合
原帖链接:http://bbs.blueidea.com/thread-2666987-1-1.html 1.因为Opera,FF3,IE8均支持display:talbe;这些特性了,因此改进的办法 ...
- FPGA IN 消费电子
消费电子: 消费电子(Consumer electronics),指供日常消费者生活使用的电子产品.消费类电子产品是指用于个人和家庭与广播.电视有关的音频和视频产品,主要包括:电视机.影碟机(VCD. ...