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 ...
随机推荐
- [01] Java语言的基本认识
0.写在前面的话 我们都知道在计算机的底层,它是识别二进制的,也就是说,计算机只能认识0和1.这主要是因为电路的逻辑只有两种状态,所以只需要0和1两个数字就可以表示低电平和高电平.而计算机是由数不清的 ...
- JDBC操作数据库之查询数据
以数据库中查找图书信息,并将信息显示在jsp页面当中为例,下面贴上代码片段: (1)在index.jsp页面代码body中只要添加如下一段代码: <a href="FindServle ...
- Ansible系列(三):YAML语法和playbook写法
html { font-family: sans-serif } body { margin: 0 } article,aside,details,figcaption,figure,footer,h ...
- 验证整数 Double 转 int 两种写法
Double 转int 1)之前一直是使用强转 Double num = Double.parseDouble(object.toString()); int n = (int)num; i ...
- 【SQL】- 基础知识梳理(六) - 游标
游标的概念 结果集,结果集就是select查询之后返回的所有行数据的集合. 游标(Cursor): 是处理数据的一种方法. 它可以定位到结果集中的某一行,对数据进行读写. 也可以移动游标定位到你需要的 ...
- 跨Storyboard调用
在开发中我们会有这种需求从一个故事板跳到另一个故事板 modal UIStoryboard *secondStoryboard = [UIStoryboard storyboardWithName:@ ...
- 极化码之tal-vardy算法(2)
上一节我们了解了tal-vardy算法的大致原理,对所要研究的二元输入无记忆对称信道进行了介绍,并着重介绍了能够避免输出爆炸灾难的合并操作,这一节我们来关注信道弱化与强化操作. [1]<Chan ...
- sql server 2000的安装
一.安装sql 二.启动sql 三.查看sql版本 RTM版本,需要打补丁 四.安装SP4
- 第七章 DAO模式
第七章 DAO模式 一.JDBC的封装 1.JDBC的封装: DAO位于业务逻辑和持久化数据之间,实现对持久化数据的访问.将数据库都封装起来,对外提供相应的接口 2.DAO模式的作用: 1.隔离业务逻 ...
- 浅谈oracle树状结构层级查询测试数据
浅谈oracle树状结构层级查询 oracle树状结构查询即层次递归查询,是sql语句经常用到的,在实际开发中组织结构实现及其层次化实现功能也是经常遇到的,虽然我是一个java程序开发者,我一直觉得只 ...