微信公众号开发-配置开发环境02

1.前言
  经过前面的配置,基本完成了一些基础配置。后面接下来就是一些开发流程了。

2.配置pom.xml

 1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4 <modelVersion>4.0.0</modelVersion> 5  6 <groupId>com.wunaozai.wechat</groupId> 7 <artifactId>WeChat</artifactId> 8 <version>0.0.1</version> 9 <packaging>jar</packaging> 10  11 <name>WeChat</name> 12 <description>微信公众号服务器</description> 13  14 <parent> 15 <groupId>org.springframework.boot</groupId> 16 <artifactId>spring-boot-starter-parent</artifactId> 17 <version>2.0.4.RELEASE</version> 18 <relativePath/> <!-- lookup parent from repository --> 19 </parent> 20  21 <properties> 22 <weixin-java-mp.version>3.1.0</weixin-java-mp.version> 23 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 24 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 25 <java.version>1.8</java.version> 26 </properties> 27  28 <dependencies> 29 <dependency> 30 <groupId>org.springframework.boot</groupId> 31 <artifactId>spring-boot-starter-web</artifactId> 32 </dependency> 33  34 <dependency> 35 <groupId>org.springframework.boot</groupId> 36 <artifactId>spring-boot-starter-thymeleaf</artifactId> 37 </dependency> 38 <dependency> 39 <groupId>com.github.binarywang</groupId> 40 <artifactId>weixin-java-mp</artifactId> 41 <version>${weixin-java-mp.version}</version> 42 </dependency> 43  44 <dependency> 45 <groupId>org.springframework.boot</groupId> 46 <artifactId>spring-boot-starter-data-redis</artifactId> 47 </dependency> 48 <dependency> 49 <groupId>org.springframework.boot</groupId> 50 <artifactId>spring-boot-starter-data-mongodb</artifactId> 51 </dependency> 52 <dependency> 53 <groupId>org.postgresql</groupId> 54 <artifactId>postgresql</artifactId> 55 </dependency> 56 <dependency> 57 <groupId>org.mybatis.spring.boot</groupId> 58 <artifactId>mybatis-spring-boot-starter</artifactId> 59 <version>1.3.2</version> 60 </dependency> 61 <dependency> 62 <groupId>org.springframework.boot</groupId> 63 <artifactId>spring-boot-starter-security</artifactId> 64 </dependency> 65 <dependency> 66 <groupId>org.springframework.security.oauth</groupId> 67 <artifactId>spring-security-oauth2</artifactId> 68 <version>2.3.3.RELEASE</version> 69 </dependency> 70 <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter --> 71 <dependency> 72 <groupId>com.github.pagehelper</groupId> 73 <artifactId>pagehelper-spring-boot-starter</artifactId> 74 <version>1.2.5</version> 75 </dependency> 76 <!-- MQTT --> 77 <dependency> 78 <groupId>org.springframework.boot</groupId> 79 <artifactId>spring-boot-starter-integration</artifactId> 80 </dependency> 81 <dependency> 82 <groupId>org.springframework.integration</groupId> 83 <artifactId>spring-integration-stream</artifactId> 84 </dependency> 85 <dependency> 86 <groupId>org.springframework.integration</groupId> 87 <artifactId>spring-integration-mqtt</artifactId> 88 </dependency> 89  90 <dependency> 91 <groupId>org.springframework.boot</groupId> 92 <artifactId>spring-boot-devtools</artifactId> 93 <scope>runtime</scope> 94 </dependency> 95 <dependency> 96 <groupId>org.springframework.boot</groupId> 97 <artifactId>spring-boot-starter-test</artifactId> 98 <scope>test</scope> 99 </dependency>100 </dependencies>101 102 <build>103 <plugins>104 <plugin>105 <groupId>org.springframework.boot</groupId>106 <artifactId>spring-boot-maven-plugin</artifactId>107 </plugin>108 </plugins>109 </build>110 111 112 </project>

  Thymeleaf 作为公众号页面前端
  weixin-java-mp 是微信公众号开发工具包
  Redis 主要用来集成OAuth2.0认证
  MongoDB 存一些JSON数据
  PostgreSQL 关系型数据,保存业务数据
  security-OAuth2 认证、权限控制
  spring-integration-mqtt MQTT客户端,用来与设备通讯

3.配置文件application.properties

  一些项目配置

 1 spring.application.name=wechat 2  3 server.port=8001 4  5 logging.path=log 6 logging.level.org.springframework.web=INFO 7 logging.level.com.github.binarywang.demo.wx.mp=DEBUG 8 logging.level.com.wunaozai.wechat=DEBUG 9 10 wechat.mp.appId=wxc60******11 wechat.mp.secret=cfe2******12 wechat.mp.token=we****13 wechat.mp.aesKey=2Bq*******14 #微信号15 #wechat.mp.accountId=gh_8*****16 #上传临时目录17 wechat.mp.tmpDir=C:/tmp18 #系统语音存放目录19 project.voice.dir=D:/tmp20 #微信语音资源下载链接前缀21 project.resource.url=http://wechat.wunaozai.com/wx/v1/voice/recv22 23 #接口配置24 wechat.mp.url=http://wechat.wunaozai.com/wx/wechat25 #JS接口安全域名配置26 wechat.mp.js=wechat.wunaozai.com27 #网页授权域名配置28 wechat.mp.web.oauth=wechat.wunaozai.com29 wechat.mp.protocol=http30 31 spring.thymeleaf.prefix=classpath:/templates/32 spring.thymeleaf.suffix=.html33 spring.thymeleaf.mode=HTML534 35 36 #postgres37 spring.datasource.url=jdbc:postgresql://172.16.23.202:5432/wechat38 spring.datasource.username=postgres39 spring.datasource.password=40 spring.datasource.driver-class-name=org.postgresql.Driver41 42 #mybatis43 mybatis.type-aliases-package=com.wunaozai.wechat.model44 mybatis.mapper-locations=classpath:com/wunaozai/wechat/mapper/*.xml45 46 #pagehelper47 pagehelper.helper-dialect=postgresql48 pagehelper.reasonable=true49 pagehelper.support-methods-arguments=true50 pagehelper.page-size-zero=true51 52 #redis53 spring.redis.database=254 spring.redis.host=172.16.23.20355 spring.redis.port=637956 spring.redis.password=f4e4********57 spring.redis.jedis.pool.max-active=858 spring.redis.jedis.pool.max-wait=6059 spring.redis.jedis.pool.max-idle=860 spring.redis.jedis.pool.min-idle=061 spring.redis.timeout=1000062 63 #mongoDB64 spring.data.mongodb.uri=mongodb://www.wunaozai.com:27777/wechat65 66 #MQTT Client67 mqtt.client.host=tcp://mqtt.wunaozai.com:188368 mqtt.client.clientid=*****admin69 mqtt.client.username=*****admin70 mqtt.client.password=*******71 mqtt.client.timeout=1072 mqtt.client.keepalive=2073 74 #tuling12375 api.tuling.url=http://openapi.tuling123.com/openapi/api/v276 api.tuling.apiKey=******77 api.tuling.userId=******

 

4.配置wechat-java-mp 工具包
  这个配置基本参考官网的Demo就可以了。我这里截图我自己的目录结构。
技术分享图片

  从目录结构可以看出,一个 WechatMpConfiguration.java 作为全局配置及微信开发工具包入口。而下方的handler是对所有微信的事件进行封装。
  例如菜单事件、关注事件、取消关注事件、扫描事件、语音事件、对话事件等。每个事件都对应一个Handler。

 1 /** 2  * 微信公众号开发 全局配置区 3  * @author wunaozai 4  * @date 2018-08-15 5 */ 6 @Configuration 7 @ConditionalOnClass(value=WxMpService.class) 8 @EnableConfigurationProperties(WechatMpProperties.class) 9 public class WechatMpConfiguration { 10  11  @Autowired 12 private WechatMpProperties properties; 13  @Autowired 14 private WechatMpLogHandler logHandler; 15  @Autowired 16 private WechatMpNullHandler nullHandler; 17  @Autowired 18 private WechatMpMenuHandler menuHandler; 19  @Autowired 20 private WechatMpMsgHandler msgHandler; 21  @Autowired 22 private WechatMpMsgVoiceHandler msgvoiceHandler; 23  @Autowired 24 private WechatMpUnsubscribeHandler unsubscribeHandler; 25  @Autowired 26 private WechatMpSubscribeHandler subscribeHandler; 27  @Autowired 28 private WechatMpScanHandler scanHandler; 29  30  @Bean 31  @ConditionalOnMissingBean 32 public WxMpConfigStorage configStorage() { 33 WxMpInMemoryConfigStorage config = new WxMpInMemoryConfigStorage(); 34  config.setAppId(properties.getAppId()); 35  config.setSecret(properties.getSecret()); 36  config.setToken(properties.getToken()); 37  config.setAesKey(properties.getAesKey()); 38 config.setTmpDirFile(new File(properties.getTmpDir())); 39 return config; 40  } 41  42  @Bean 43  @ConditionalOnMissingBean 44 public WxMpService wxmpService(WxMpConfigStorage config) { 45 WxMpService service = new WxMpServiceImpl(); 46  service.setWxMpConfigStorage(config); 47 return service; 48  } 49 /* 50  @Bean 51  @ConditionalOnMissingBean 52  public WxMpDeviceService wxMpDeviceService(WxMpService wxmpService) { 53  WxMpDeviceService service = new WxMpDeviceServiceImpl(wxmpService); 54  return service; 55  } 56 */ 57  58  @Bean 59 public WxMpMessageRouter router(WxMpService wxmpService) { 60  61 final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxmpService); 62  63 //记录所有事件日志(异步执行) 64 newRouter.rule().async(false).handler(this.logHandler).next(); 65  66 //当前项目Wifi故事机 只处理自定义菜单事件、关注/取关事件、文本和语音信息 67 //自定义菜单事件 68 newRouter.rule().async(false).msgType(XmlMsgType.EVENT) 69  .event(MenuButtonType.CLICK).handler(menuHandler).end(); 70 //关注事件 71 newRouter.rule().async(false).msgType(XmlMsgType.EVENT) 72  .event(EventType.SUBSCRIBE).handler(subscribeHandler).end(); 73 //取消关注事件 74 newRouter.rule().async(false).msgType(XmlMsgType.EVENT) 75  .event(EventType.UNSUBSCRIBE).handler(unsubscribeHandler).end(); 76 //处理扫描事件 77 newRouter.rule().async(false).msgType(XmlMsgType.EVENT) 78  .event(EventType.SCANCODE_WAITMSG).handler(scanHandler).end(); 79  80 //这里过滤掉所有事件 81 newRouter.rule().async(false).msgType(XmlMsgType.EVENT).handler(nullHandler).end(); 82  83 //处理语音信息 84 newRouter.rule().async(false).msgType(XmlMsgType.VOICE).handler(msgvoiceHandler).end(); 85  86 //这里过滤掉所有输入 87 newRouter.rule().async(false).handler(msgHandler).end(); 88  89 /* 90  //接收客服会话管理事件 91  newRouter.rule().async(false).msgType(XmlMsgType.EVENT) 92  .event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION) 93  .handler(kfsessionHandler).end(); 94  newRouter.rule().async(false).msgType(XmlMsgType.EVENT) 95  .event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION) 96  .handler(kfsessionHandler).end(); 97  newRouter.rule().async(false).msgType(XmlMsgType.EVENT) 98  .event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION) 99  .handler(kfsessionHandler).end();100 101  //门店审核事件102  newRouter.rule().async(false).msgType(XmlMsgType.EVENT)103  .event(MenuButtonType.CLICK).handler(nullHandler).end();104 105  //自定义菜单事件106  newRouter.rule().async(false).msgType(XmlMsgType.EVENT)107  .event(MenuButtonType.CLICK).handler(menuHandler).end();108 109  //点击菜单链接事件110  newRouter.rule().async(false).msgType(XmlMsgType.EVENT)111  .event(MenuButtonType.VIEW).handler(nullHandler).end();112 113  //关注事件114  newRouter.rule().async(false).msgType(XmlMsgType.EVENT)115  .event(EventType.SUBSCRIBE).handler(subscribeHandler).end();116 117  //取消关注事件118  newRouter.rule().async(false).msgType(XmlMsgType.EVENT)119  .event(EventType.UNSUBSCRIBE).handler(unsubscribeHandler).end();120 121  //上报地理位置事件122  newRouter.rule().async(false).msgType(XmlMsgType.EVENT)123  .event(EventType.LOCATION).handler(locationHandler).end();124 125  //接收地理位置消息126  newRouter.rule().async(false).msgType(XmlMsgType.LOCATION)127  .handler(locationHandler).end();128 129  //扫码事件130  newRouter.rule().async(false).msgType(XmlMsgType.EVENT)131  .event(EventType.SCAN).handler(nullHandler).end();132 133  //默认134  newRouter.rule().async(false).handler(msgHandler).end();135 */136 return newRouter;137  }138 }

 

5. 关注事件举例
  我们在WechatMpConfiguration.java中注册了一个关注事件处理Handler。

newRouter.rule().async(false).msgType(XmlMsgType.EVENT).event(EventType.SUBSCRIBE).handler(subscribeHandler).end();

 

 1 /** 2  * 用户关注事件 3  * @author wunaozai 4  * @date 2018-08-15 5 */ 6 @Component 7 public class WechatMpSubscribeHandler extends AbstractHandler { 8  9  @Autowired10 private WechatUserService wechatuserService;11 12  @Override13 public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxmpService,14 WxSessionManager sessionManager) throws WxErrorException {15 //log.info("新关注用户 openid: " + wxMessage.getFromUser());16 //获取微信用户基本信息17 WxMpUser user = wxmpService.getUserService().userInfo(wxMessage.getFromUser(), null);18 if(user != null) {19 //可以添加关注用户到本地数据库20 WechatUserPoModel po = new WechatUserPoModel();21  po.setOpenid(user.getOpenId());22 po.setStatus(true);23  wechatuserService.selectOneAndInsertIt(po);24 25  po.setNickname(user.getNickname());26  po.setSex_desc(user.getSexDesc());27  po.setSex(user.getSex());28  po.setCity(user.getCity());29  po.setProvince(user.getProvince());30  po.setCountry(user.getCountry());31  po.setHead_img_url(user.getHeadImgUrl());32  wechatuserService.updateOneByOpenid(po);33 34  }35 try {36 String msg = "您好," + user.getNickname() + 37 "!\n欢迎使用杰理故事机/:heart\n如果是第一次使用,请点击下方按钮,按提示步骤进行操作。";38 return new WechatMpTextBuilder().build(msg, wxMessage, wxmpService);39 } catch (Exception e) {40  log.error(e.getMessage());41  }42 return null;43  }44 }

 

6. 扫码事件举例
  类似关注事件,扫码事件,也是需要在配置类,注册一个Handler。

newRouter.rule().async(false).msgType(XmlMsgType.EVENT).event(EventType.SCANCODE_WAITMSG).handler(scanHandler).end();

 

 1 @Component 2 public class WechatMpScanHandler extends AbstractHandler { 3  4  @Autowired 5 private WechatUserCtrlService wechatuserctrlService; 6  7  @Override 8 public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxmpService, 9 WxSessionManager sessionManager) throws WxErrorException {10 String scan_type = wxMessage.getScanCodeInfo().getScanType();11 String scan_result = wxMessage.getScanCodeInfo().getScanResult();12 String info = "非本公众号内二维码";13 try {14 if(scan_type.equalsIgnoreCase("qrcode")) {15 ScanResult result = TranUtils.tranJSONObejct(scan_result, ScanResult.class);16 String openid = wxMessage.getFromUser();17 if(result.getK().equalsIgnoreCase("share")) {18 //设备分享功能19 try {20 boolean flag = wechatuserctrlService.bindDeviceByShareKey(openid, result.getV());21 if(flag == true) {22 info = "绑定成功.";23 }else {24 info = "绑定失败.";25  }26 }catch (Exception e) {27 info = e.getMessage();28  }29  }30  }31 }catch (Exception e) {32  e.printStackTrace();33  }34 return new WechatMpTextBuilder().build(info, wxMessage, wxmpService);35  }36 }

 

7. 自定义菜单
  这个就分为创建自定义菜单和自定义菜单事件。创建自定义菜单,这个需要先构造自定义菜单格式,然后POST到微信。

 1 @RestController 2 @RequestMapping("/wx/wechat") 3 public class WechatMenuController implements WxMpMenuService { 4  5  @Autowired 6 private WxMpService wxmpService; 7 @Value(value="${wechat.mp.url}") 8 private String url; 9 10 @GetMapping("/menu")11 public String menuCreateSample() throws WxErrorException {12 WxMenu menu = new WxMenu();13 WxMenuButton story = new WxMenuButton();14  story.setType(MenuButtonType.VIEW);15 story.setName("听故事");16  story.setKey(WechatMpMenuConfig.M_STORY);17 story.setUrl(url + "/story/index");18 19 WxMenuButton device_1 = new WxMenuButton();20  device_1.setType(MenuButtonType.VIEW);21 device_1.setName("联网配置");22  device_1.setKey(WechatMpMenuConfig.M_DEVICE_1);23 device_1.setUrl(url + "/airkiss");24 WxMenuButton device_2 = new WxMenuButton();25  device_2.setType(MenuButtonType.VIEW);26 device_2.setName("设备绑定");27  device_2.setKey(WechatMpMenuConfig.M_DEVICE_2);28 device_2.setUrl(url + "/scan_bind");29 WxMenuButton device_3 = new WxMenuButton();30  device_3.setType(MenuButtonType.SCANCODE_WAITMSG);31 device_3.setName("二维码扫描");32  device_3.setKey(WechatMpMenuConfig.M_DEVICE_3);33 WxMenuButton device_4 = new WxMenuButton();34  device_4.setType(MenuButtonType.VIEW);35 device_4.setName("我的设备");36  device_4.setKey(WechatMpMenuConfig.M_DEVICE_4);37 device_4.setUrl(url + "/story/index#/user");38 WxMenuButton device = new WxMenuButton();39  device.setType(MenuButtonType.CLICK);40 device.setName("设备功能");41  device.setKey(WechatMpMenuConfig.M_DEVICE);42  device.getSubButtons().add(device_1);43  device.getSubButtons().add(device_2);44  device.getSubButtons().add(device_3);45  device.getSubButtons().add(device_4);46 47 48 WxMenuButton other_1 = new WxMenuButton();49  other_1.setType(MenuButtonType.VIEW);50 other_1.setName("常见问题");51  other_1.setKey(WechatMpMenuConfig.M_OTHER_1);52 other_1.setUrl("https://mp.weixin.qq.com/s/YTGis2OK2Jtx-4NnnRqukw");53 WxMenuButton other_2 = new WxMenuButton();54  other_2.setType(MenuButtonType.VIEW);55 other_2.setName("意见反馈");56  other_2.setKey(WechatMpMenuConfig.M_OTHER_2);57 other_2.setUrl(url + "/feedback");58 WxMenuButton other_3 = new WxMenuButton();59  other_3.setType(MenuButtonType.VIEW);60 other_3.setName("官网");61  other_3.setKey(WechatMpMenuConfig.M_OTHER_3);62 other_3.setUrl("http://www.wunaozai.com/");63 WxMenuButton other_4 = new WxMenuButton();64  other_4.setType(MenuButtonType.CLICK);65 other_4.setName("接收新信息");66  other_4.setKey(WechatMpMenuConfig.M_OTHER_NEW_MSG);67 WxMenuButton other = new WxMenuButton();68  other.setType(MenuButtonType.CLICK);69 other.setName("更多");70  other.setKey(WechatMpMenuConfig.M_OTHER);71  other.getSubButtons().add(other_1);72  other.getSubButtons().add(other_2);73  other.getSubButtons().add(other_3);74  other.getSubButtons().add(other_4);75 76 77  menu.getButtons().add(story);78  menu.getButtons().add(device);79  menu.getButtons().add(other);80 81  wxmpService.getMenuService().menuCreate(menu);82 return "ok";83   }84   //...85 }

  自定义菜单事件Handler

 1 /** 2  * 菜单功能 3  * @author wunaozai 4  * @date 2018-08-15 5 */ 6 @Component 7 public class WechatMpMenuHandler extends AbstractHandler { 8  9  @Override10 public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxmpService,11 WxSessionManager sessionManager) throws WxErrorException {12 log.info("微信公众号 菜单功能");13 String msg = String.format("Type: %s, Event: %s, Key: %s", 14  wxMessage.getMsgType(), wxMessage.getEvent(), wxMessage.getEventKey());15 if(MenuButtonType.VIEW.equals(wxMessage.getEvent())) {16 //如果是跳转类按钮的就不进行处理17 return null;18  }19 if(wxMessage.getEventKey().equalsIgnoreCase(WechatMpMenuConfig.M_OTHER_NEW_MSG)) {20 //TODO: 读取数据库,下发信息,并删除21 //如果没有信息的,提示没有未读信息22 String info = "暂无新消息.";23 return new WechatMpTextBuilder().build(info, wxMessage, wxmpService);24  }25 String info = "按下“"+wxMessage.getEventKey()+"”按钮,将跳转到指定的公众号页面.";26 return new WechatMpTextBuilder().build(info, wxMessage, wxmpService);27  }28 29 }

  自定义菜单注册

newRouter.rule().async(false).msgType(XmlMsgType.EVENT).event(MenuButtonType.CLICK).handler(menuHandler).end();

  公众号后台-菜单分析

技术分享图片

 

相关文章