configs;
+
+ @Data
+ public static class MpConfig {
+ /**
+ * 设置微信公众号的appid
+ */
+ private String appId;
+
+ /**
+ * 设置微信公众号的app secret
+ */
+ private String secret;
+
+ /**
+ * 设置微信公众号的token
+ */
+ private String token;
+
+ /**
+ * 设置微信公众号的EncodingAESKey
+ */
+ private String aesKey;
+ }
+
+ @Override
+ public String toString() {
+ return JsonUtils.toJson(this);
+ }
+}
diff --git a/src/main/java/com/rymcu/vertical/wx/mp/controller/WxMenuController.java b/src/main/java/com/rymcu/vertical/wx/mp/controller/WxMenuController.java
new file mode 100644
index 0000000..03c2372
--- /dev/null
+++ b/src/main/java/com/rymcu/vertical/wx/mp/controller/WxMenuController.java
@@ -0,0 +1,188 @@
+package com.rymcu.vertical.wx.mp.controller;
+
+import lombok.AllArgsConstructor;
+import me.chanjar.weixin.common.api.WxConsts;
+import me.chanjar.weixin.common.bean.menu.WxMenu;
+import me.chanjar.weixin.common.bean.menu.WxMenuButton;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult;
+import me.chanjar.weixin.mp.bean.menu.WxMpMenu;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType;
+
+/**
+ * @author Binary Wang(https://github.com/binarywang)
+ */
+@AllArgsConstructor
+@RestController
+@RequestMapping("/wx/menu/{appid}")
+public class WxMenuController {
+ private final WxMpService wxService;
+
+ /**
+ *
+ * 自定义菜单创建接口
+ * 详情请见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN
+ * 如果要创建个性化菜单,请设置matchrule属性
+ * 详情请见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
+ *
+ *
+ * @return 如果是个性化菜单,则返回menuid,否则返回null
+ */
+ @PostMapping("/create")
+ public String menuCreate(@PathVariable String appid, @RequestBody WxMenu menu) throws WxErrorException {
+ return this.wxService.switchoverTo(appid).getMenuService().menuCreate(menu);
+ }
+
+ @GetMapping("/create")
+ public String menuCreateSample(@PathVariable String appid) throws WxErrorException, MalformedURLException {
+ WxMenu menu = new WxMenu();
+ WxMenuButton button1 = new WxMenuButton();
+ button1.setType(MenuButtonType.CLICK);
+ button1.setName("今日歌曲");
+ button1.setKey("V1001_TODAY_MUSIC");
+
+// WxMenuButton button2 = new WxMenuButton();
+// button2.setType(WxConsts.BUTTON_MINIPROGRAM);
+// button2.setName("小程序");
+// button2.setAppId("wx286b93c14bbf93aa");
+// button2.setPagePath("pages/lunar/index.html");
+// button2.setUrl("http://mp.weixin.qq.com");
+
+ WxMenuButton button3 = new WxMenuButton();
+ button3.setName("菜单");
+
+ menu.getButtons().add(button1);
+// menu.getButtons().add(button2);
+ menu.getButtons().add(button3);
+
+ WxMenuButton button31 = new WxMenuButton();
+ button31.setType(MenuButtonType.VIEW);
+ button31.setName("搜索");
+ button31.setUrl("http://www.soso.com/");
+
+ WxMenuButton button32 = new WxMenuButton();
+ button32.setType(MenuButtonType.VIEW);
+ button32.setName("视频");
+ button32.setUrl("http://v.qq.com/");
+
+ WxMenuButton button33 = new WxMenuButton();
+ button33.setType(MenuButtonType.CLICK);
+ button33.setName("赞一下我们");
+ button33.setKey("V1001_GOOD");
+
+ WxMenuButton button34 = new WxMenuButton();
+ button34.setType(MenuButtonType.VIEW);
+ button34.setName("获取用户信息");
+
+ ServletRequestAttributes servletRequestAttributes =
+ (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+ if (servletRequestAttributes != null) {
+ HttpServletRequest request = servletRequestAttributes.getRequest();
+ URL requestURL = new URL(request.getRequestURL().toString());
+ String url = this.wxService.switchoverTo(appid).oauth2buildAuthorizationUrl(
+ String.format("%s://%s/wx/redirect/%s/greet", requestURL.getProtocol(), requestURL.getHost(), appid),
+ WxConsts.OAuth2Scope.SNSAPI_USERINFO, null);
+ button34.setUrl(url);
+ }
+
+ button3.getSubButtons().add(button31);
+ button3.getSubButtons().add(button32);
+ button3.getSubButtons().add(button33);
+ button3.getSubButtons().add(button34);
+
+ this.wxService.switchover(appid);
+ return this.wxService.getMenuService().menuCreate(menu);
+ }
+
+ /**
+ *
+ * 自定义菜单创建接口
+ * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN
+ * 如果要创建个性化菜单,请设置matchrule属性
+ * 详情请见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
+ *
+ *
+ * @return 如果是个性化菜单,则返回menuid,否则返回null
+ */
+ @PostMapping("/createByJson")
+ public String menuCreate(@PathVariable String appid, @RequestBody String json) throws WxErrorException {
+ return this.wxService.switchoverTo(appid).getMenuService().menuCreate(json);
+ }
+
+ /**
+ *
+ * 自定义菜单删除接口
+ * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141015&token=&lang=zh_CN
+ *
+ */
+ @GetMapping("/delete")
+ public void menuDelete(@PathVariable String appid) throws WxErrorException {
+ this.wxService.switchoverTo(appid).getMenuService().menuDelete();
+ }
+
+ /**
+ *
+ * 删除个性化菜单接口
+ * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
+ *
+ *
+ * @param menuId 个性化菜单的menuid
+ */
+ @GetMapping("/delete/{menuId}")
+ public void menuDelete(@PathVariable String appid, @PathVariable String menuId) throws WxErrorException {
+ this.wxService.switchoverTo(appid).getMenuService().menuDelete(menuId);
+ }
+
+ /**
+ *
+ * 自定义菜单查询接口
+ * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141014&token=&lang=zh_CN
+ *
+ */
+ @GetMapping("/get")
+ public WxMpMenu menuGet(@PathVariable String appid) throws WxErrorException {
+ return this.wxService.switchoverTo(appid).getMenuService().menuGet();
+ }
+
+ /**
+ *
+ * 测试个性化菜单匹配结果
+ * 详情请见: http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
+ *
+ *
+ * @param userid 可以是粉丝的OpenID,也可以是粉丝的微信号。
+ */
+ @GetMapping("/menuTryMatch/{userid}")
+ public WxMenu menuTryMatch(@PathVariable String appid, @PathVariable String userid) throws WxErrorException {
+ return this.wxService.switchoverTo(appid).getMenuService().menuTryMatch(userid);
+ }
+
+ /**
+ *
+ * 获取自定义菜单配置接口
+ * 本接口将会提供公众号当前使用的自定义菜单的配置,如果公众号是通过API调用设置的菜单,则返回菜单的开发配置,而如果公众号是在公众平台官网通过网站功能发布菜单,则本接口返回运营者设置的菜单配置。
+ * 请注意:
+ * 1、第三方平台开发者可以通过本接口,在旗下公众号将业务授权给你后,立即通过本接口检测公众号的自定义菜单配置,并通过接口再次给公众号设置好自动回复规则,以提升公众号运营者的业务体验。
+ * 2、本接口与自定义菜单查询接口的不同之处在于,本接口无论公众号的接口是如何设置的,都能查询到接口,而自定义菜单查询接口则仅能查询到使用API设置的菜单配置。
+ * 3、认证/未认证的服务号/订阅号,以及接口测试号,均拥有该接口权限。
+ * 4、从第三方平台的公众号登录授权机制上来说,该接口从属于消息与菜单权限集。
+ * 5、本接口中返回的图片/语音/视频为临时素材(临时素材每次获取都不同,3天内有效,通过素材管理-获取临时素材接口来获取这些素材),本接口返回的图文消息为永久素材素材(通过素材管理-获取永久素材接口来获取这些素材)。
+ * 接口调用请求说明:
+ * http请求方式: GET(请使用https协议)
+ * https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=ACCESS_TOKEN
+ *
+ */
+ @GetMapping("/getSelfMenuInfo")
+ public WxMpGetSelfMenuInfoResult getSelfMenuInfo(@PathVariable String appid) throws WxErrorException {
+ return this.wxService.switchoverTo(appid).getMenuService().getSelfMenuInfo();
+ }
+}
diff --git a/src/main/java/com/rymcu/vertical/wx/mp/controller/WxPortalController.java b/src/main/java/com/rymcu/vertical/wx/mp/controller/WxPortalController.java
new file mode 100644
index 0000000..524549a
--- /dev/null
+++ b/src/main/java/com/rymcu/vertical/wx/mp/controller/WxPortalController.java
@@ -0,0 +1,116 @@
+package com.rymcu.vertical.wx.mp.controller;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.log4j.Log4j;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.mp.api.WxMpMessageRouter;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+
+/**
+ * @author Binary Wang(https://github.com/binarywang)
+ */
+@Slf4j
+@AllArgsConstructor
+@RestController
+@RequestMapping("/wx/portal/{appid}")
+public class WxPortalController {
+ private final WxMpService wxService;
+ private final WxMpMessageRouter messageRouter;
+
+ @GetMapping(produces = "text/plain;charset=utf-8")
+ public String authGet(@PathVariable String appid,
+ @RequestParam(name = "signature", required = false) String signature,
+ @RequestParam(name = "timestamp", required = false) String timestamp,
+ @RequestParam(name = "nonce", required = false) String nonce,
+ @RequestParam(name = "echostr", required = false) String echostr) {
+
+ log.info("\n接收到来自微信服务器的认证消息:[{}, {}, {}, {}]", signature,
+ timestamp, nonce, echostr);
+ if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
+ throw new IllegalArgumentException("请求参数非法,请核实!");
+ }
+
+ if (!this.wxService.switchover(appid)) {
+ throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
+ }
+
+ if (wxService.checkSignature(timestamp, nonce, signature)) {
+ return echostr;
+ }
+
+ return "非法请求";
+ }
+
+ @PostMapping(produces = "application/xml; charset=UTF-8")
+ public String post(@PathVariable String appid,
+ @RequestBody String requestBody,
+ @RequestParam("signature") String signature,
+ @RequestParam("timestamp") String timestamp,
+ @RequestParam("nonce") String nonce,
+ @RequestParam("openid") String openid,
+ @RequestParam(name = "encrypt_type", required = false) String encType,
+ @RequestParam(name = "msg_signature", required = false) String msgSignature) {
+ log.info("\n接收微信请求:[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}],"
+ + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
+ openid, signature, encType, msgSignature, timestamp, nonce, requestBody);
+
+ if (!this.wxService.switchover(appid)) {
+ throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
+ }
+
+ if (!wxService.checkSignature(timestamp, nonce, signature)) {
+ throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
+ }
+
+ String out = null;
+ if (encType == null) {
+ // 明文传输的消息
+ WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
+ WxMpXmlOutMessage outMessage = this.route(inMessage);
+ if (outMessage == null) {
+ return "";
+ }
+
+ out = outMessage.toXml();
+ } else if ("aes".equalsIgnoreCase(encType)) {
+ // aes加密的消息
+ WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxService.getWxMpConfigStorage(),
+ timestamp, nonce, msgSignature);
+ log.debug("\n消息解密后内容为:\n{} ", inMessage.toString());
+ WxMpXmlOutMessage outMessage = this.route(inMessage);
+ if (outMessage == null) {
+ return "";
+ }
+
+ out = outMessage.toEncryptedXml(wxService.getWxMpConfigStorage());
+ }
+
+ log.debug("\n组装回复信息:{}", out);
+ return out;
+ }
+
+ private WxMpXmlOutMessage route(WxMpXmlMessage message) {
+ try {
+ return this.messageRouter.route(message);
+ } catch (Exception e) {
+ log.error("路由消息时出现异常!", e);
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/vertical/wx/mp/controller/WxRedirectController.java b/src/main/java/com/rymcu/vertical/wx/mp/controller/WxRedirectController.java
new file mode 100644
index 0000000..35bf6b4
--- /dev/null
+++ b/src/main/java/com/rymcu/vertical/wx/mp/controller/WxRedirectController.java
@@ -0,0 +1,42 @@
+package com.rymcu.vertical.wx.mp.controller;
+
+import lombok.AllArgsConstructor;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
+import me.chanjar.weixin.mp.bean.result.WxMpUser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import javax.xml.ws.Action;
+
+/**
+ * @author Edward
+ */
+@AllArgsConstructor
+@Controller
+@RequestMapping("/wx/redirect/{appid}")
+public class WxRedirectController {
+ private final WxMpService wxService;
+
+ @RequestMapping("/greet")
+ public String greetUser(@PathVariable String appid, @RequestParam String code, ModelMap map) {
+ if (!this.wxService.switchover(appid)) {
+ throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
+ }
+
+ try {
+ WxMpOAuth2AccessToken accessToken = wxService.oauth2getAccessToken(code);
+ WxMpUser user = wxService.oauth2getUserInfo(accessToken, null);
+ map.put("user", user);
+ } catch (WxErrorException e) {
+ e.printStackTrace();
+ }
+
+ return "greet_user";
+ }
+}
diff --git a/src/main/java/com/rymcu/vertical/wx/mp/error/ErrorController.java b/src/main/java/com/rymcu/vertical/wx/mp/error/ErrorController.java
new file mode 100644
index 0000000..03b8bad
--- /dev/null
+++ b/src/main/java/com/rymcu/vertical/wx/mp/error/ErrorController.java
@@ -0,0 +1,29 @@
+package com.rymcu.vertical.wx.mp.error;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+/**
+ *
+ * 出错页面控制器
+ * Created by Binary Wang on 2018/8/25.
+ *
+ *
+ * @author Binary Wang
+ */
+@Controller
+@RequestMapping("/error")
+public class ErrorController {
+
+ @GetMapping(value = "/404")
+ public String error404() {
+ return "error";
+ }
+
+ @GetMapping(value = "/500")
+ public String error500() {
+ return "error";
+ }
+
+}
diff --git a/src/main/java/com/rymcu/vertical/wx/mp/error/ErrorPageConfiguration.java b/src/main/java/com/rymcu/vertical/wx/mp/error/ErrorPageConfiguration.java
new file mode 100644
index 0000000..2502a00
--- /dev/null
+++ b/src/main/java/com/rymcu/vertical/wx/mp/error/ErrorPageConfiguration.java
@@ -0,0 +1,27 @@
+package com.rymcu.vertical.wx.mp.error;
+
+import org.springframework.boot.web.server.ErrorPage;
+import org.springframework.boot.web.server.ErrorPageRegistrar;
+import org.springframework.boot.web.server.ErrorPageRegistry;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
+
+/**
+ *
+ * 配置错误状态与对应访问路径
+ * Created by Binary Wang on 2018/8/25.
+ *
+ *
+ * @author Binary Wang
+ */
+@Component
+public class ErrorPageConfiguration implements ErrorPageRegistrar {
+ @Override
+ public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
+ errorPageRegistry.addErrorPages(
+ new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"),
+ new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500")
+ );
+ }
+
+}
diff --git a/src/main/java/com/rymcu/vertical/wx/mp/handler/AbstractHandler.java b/src/main/java/com/rymcu/vertical/wx/mp/handler/AbstractHandler.java
new file mode 100644
index 0000000..2149b1c
--- /dev/null
+++ b/src/main/java/com/rymcu/vertical/wx/mp/handler/AbstractHandler.java
@@ -0,0 +1,12 @@
+package com.rymcu.vertical.wx.mp.handler;
+
+import me.chanjar.weixin.mp.api.WxMpMessageHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Binary Wang(https://github.com/binarywang)
+ */
+public abstract class AbstractHandler implements WxMpMessageHandler {
+ protected Logger logger = LoggerFactory.getLogger(getClass());
+}
diff --git a/src/main/java/com/rymcu/vertical/wx/mp/handler/KfSessionHandler.java b/src/main/java/com/rymcu/vertical/wx/mp/handler/KfSessionHandler.java
new file mode 100644
index 0000000..0423997
--- /dev/null
+++ b/src/main/java/com/rymcu/vertical/wx/mp/handler/KfSessionHandler.java
@@ -0,0 +1,25 @@
+package com.rymcu.vertical.wx.mp.handler;
+
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @author Binary Wang(https://github.com/binarywang)
+ */
+@Component
+public class KfSessionHandler extends AbstractHandler {
+
+ @Override
+ public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+ Map context, WxMpService wxMpService,
+ WxSessionManager sessionManager) {
+ //TODO 对会话做处理
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/vertical/wx/mp/handler/LocationHandler.java b/src/main/java/com/rymcu/vertical/wx/mp/handler/LocationHandler.java
new file mode 100644
index 0000000..fd0330f
--- /dev/null
+++ b/src/main/java/com/rymcu/vertical/wx/mp/handler/LocationHandler.java
@@ -0,0 +1,44 @@
+package com.rymcu.vertical.wx.mp.handler;
+
+import com.rymcu.vertical.wx.mp.builder.TextBuilder;
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
+
+/**
+ * @author Binary Wang(https://github.com/binarywang)
+ */
+@Component
+public class LocationHandler extends AbstractHandler {
+
+ @Override
+ public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+ Map context, WxMpService wxMpService,
+ WxSessionManager sessionManager) {
+ if (wxMessage.getMsgType().equals(XmlMsgType.LOCATION)) {
+ //TODO 接收处理用户发送的地理位置消息
+ try {
+ String content = "感谢反馈,您的的地理位置已收到!";
+ return new TextBuilder().build(content, wxMessage, null);
+ } catch (Exception e) {
+ this.logger.error("位置消息接收处理失败", e);
+ return null;
+ }
+ }
+
+ //上报地理位置事件
+ this.logger.info("上报地理位置,纬度 : {},经度 : {},精度 : {}",
+ wxMessage.getLatitude(), wxMessage.getLongitude(), String.valueOf(wxMessage.getPrecision()));
+
+ //TODO 可以将用户地理位置信息保存到本地数据库,以便以后使用
+
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/vertical/wx/mp/handler/LogHandler.java b/src/main/java/com/rymcu/vertical/wx/mp/handler/LogHandler.java
new file mode 100644
index 0000000..f405a19
--- /dev/null
+++ b/src/main/java/com/rymcu/vertical/wx/mp/handler/LogHandler.java
@@ -0,0 +1,25 @@
+package com.rymcu.vertical.wx.mp.handler;
+
+import com.rymcu.vertical.wx.mp.utils.JsonUtils;
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @author Binary Wang(https://github.com/binarywang)
+ */
+@Component
+public class LogHandler extends AbstractHandler {
+ @Override
+ public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+ Map context, WxMpService wxMpService,
+ WxSessionManager sessionManager) {
+ this.logger.info("\n接收到请求消息,内容:{}", JsonUtils.toJson(wxMessage));
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/vertical/wx/mp/handler/MenuHandler.java b/src/main/java/com/rymcu/vertical/wx/mp/handler/MenuHandler.java
new file mode 100644
index 0000000..e100914
--- /dev/null
+++ b/src/main/java/com/rymcu/vertical/wx/mp/handler/MenuHandler.java
@@ -0,0 +1,35 @@
+package com.rymcu.vertical.wx.mp.handler;
+
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+import static me.chanjar.weixin.common.api.WxConsts.EventType;
+
+/**
+ * @author Binary Wang(https://github.com/binarywang)
+ */
+@Component
+public class MenuHandler extends AbstractHandler {
+
+ @Override
+ public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+ Map context, WxMpService weixinService,
+ WxSessionManager sessionManager) {
+ String msg = String.format("type:%s, event:%s, key:%s",
+ wxMessage.getMsgType(), wxMessage.getEvent(),
+ wxMessage.getEventKey());
+ if (EventType.VIEW.equals(wxMessage.getEvent())) {
+ return null;
+ }
+
+ return WxMpXmlOutMessage.TEXT().content(msg)
+ .fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
+ .build();
+ }
+
+}
diff --git a/src/main/java/com/rymcu/vertical/wx/mp/handler/MsgHandler.java b/src/main/java/com/rymcu/vertical/wx/mp/handler/MsgHandler.java
new file mode 100644
index 0000000..74cde99
--- /dev/null
+++ b/src/main/java/com/rymcu/vertical/wx/mp/handler/MsgHandler.java
@@ -0,0 +1,52 @@
+package com.rymcu.vertical.wx.mp.handler;
+
+import com.rymcu.vertical.wx.mp.builder.TextBuilder;
+import com.rymcu.vertical.wx.mp.utils.JsonUtils;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
+
+/**
+ * @author Binary Wang(https://github.com/binarywang)
+ */
+@Component
+public class MsgHandler extends AbstractHandler {
+
+ @Override
+ public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+ Map context, WxMpService weixinService,
+ WxSessionManager sessionManager) {
+
+ if (!wxMessage.getMsgType().equals(XmlMsgType.EVENT)) {
+ //TODO 可以选择将消息保存到本地
+ }
+
+ //当用户输入关键词如“你好”,“客服”等,并且有客服在线时,把消息转发给在线客服
+ try {
+ if (StringUtils.startsWithAny(wxMessage.getContent(), "你好", "客服")
+ && weixinService.getKefuService().kfOnlineList()
+ .getKfOnlineList().size() > 0) {
+ return WxMpXmlOutMessage.TRANSFER_CUSTOMER_SERVICE()
+ .fromUser(wxMessage.getToUser())
+ .toUser(wxMessage.getFromUser()).build();
+ }
+ } catch (WxErrorException e) {
+ e.printStackTrace();
+ }
+
+ //TODO 组装回复消息
+ String content = "收到信息内容:" + JsonUtils.toJson(wxMessage);
+
+ return new TextBuilder().build(content, wxMessage, weixinService);
+
+ }
+
+}
diff --git a/src/main/java/com/rymcu/vertical/wx/mp/handler/NullHandler.java b/src/main/java/com/rymcu/vertical/wx/mp/handler/NullHandler.java
new file mode 100644
index 0000000..23bbdad
--- /dev/null
+++ b/src/main/java/com/rymcu/vertical/wx/mp/handler/NullHandler.java
@@ -0,0 +1,24 @@
+package com.rymcu.vertical.wx.mp.handler;
+
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @author Binary Wang(https://github.com/binarywang)
+ */
+@Component
+public class NullHandler extends AbstractHandler {
+
+ @Override
+ public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+ Map context, WxMpService wxMpService,
+ WxSessionManager sessionManager) {
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/vertical/wx/mp/handler/ScanHandler.java b/src/main/java/com/rymcu/vertical/wx/mp/handler/ScanHandler.java
new file mode 100644
index 0000000..99bc85b
--- /dev/null
+++ b/src/main/java/com/rymcu/vertical/wx/mp/handler/ScanHandler.java
@@ -0,0 +1,25 @@
+package com.rymcu.vertical.wx.mp.handler;
+
+import java.util.Map;
+
+import org.springframework.stereotype.Component;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+
+/**
+ * @author Binary Wang(https://github.com/binarywang)
+ */
+@Component
+public class ScanHandler extends AbstractHandler {
+
+ @Override
+ public WxMpXmlOutMessage handle(WxMpXmlMessage wxMpXmlMessage, Map map,
+ WxMpService wxMpService, WxSessionManager wxSessionManager) throws WxErrorException {
+ // 扫码事件处理
+ return null;
+ }
+}
diff --git a/src/main/java/com/rymcu/vertical/wx/mp/handler/StoreCheckNotifyHandler.java b/src/main/java/com/rymcu/vertical/wx/mp/handler/StoreCheckNotifyHandler.java
new file mode 100644
index 0000000..d036ea7
--- /dev/null
+++ b/src/main/java/com/rymcu/vertical/wx/mp/handler/StoreCheckNotifyHandler.java
@@ -0,0 +1,27 @@
+package com.rymcu.vertical.wx.mp.handler;
+
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * 门店审核事件处理
+ *
+ * @author Binary Wang(https://github.com/binarywang)
+ */
+@Component
+public class StoreCheckNotifyHandler extends AbstractHandler {
+
+ @Override
+ public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+ Map context, WxMpService wxMpService,
+ WxSessionManager sessionManager) {
+ // TODO 处理门店审核事件
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/vertical/wx/mp/handler/SubscribeHandler.java b/src/main/java/com/rymcu/vertical/wx/mp/handler/SubscribeHandler.java
new file mode 100644
index 0000000..d4fac61
--- /dev/null
+++ b/src/main/java/com/rymcu/vertical/wx/mp/handler/SubscribeHandler.java
@@ -0,0 +1,71 @@
+package com.rymcu.vertical.wx.mp.handler;
+
+import java.util.Map;
+
+import com.rymcu.vertical.wx.mp.builder.TextBuilder;
+import org.springframework.stereotype.Component;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import me.chanjar.weixin.mp.bean.result.WxMpUser;
+
+/**
+ * @author Binary Wang(https://github.com/binarywang)
+ */
+@Component
+public class SubscribeHandler extends AbstractHandler {
+
+ @Override
+ public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+ Map context, WxMpService weixinService,
+ WxSessionManager sessionManager) throws WxErrorException {
+
+ this.logger.info("新关注用户 OPENID: " + wxMessage.getFromUser());
+
+ // 获取微信用户基本信息
+ try {
+ WxMpUser userWxInfo = weixinService.getUserService()
+ .userInfo(wxMessage.getFromUser(), null);
+ if (userWxInfo != null) {
+ // TODO 可以添加关注用户到本地数据库
+ }
+ } catch (WxErrorException e) {
+ if (e.getError().getErrorCode() == 48001) {
+ this.logger.info("该公众号没有获取用户信息权限!");
+ }
+ }
+
+
+ WxMpXmlOutMessage responseResult = null;
+ try {
+ responseResult = this.handleSpecial(wxMessage);
+ } catch (Exception e) {
+ this.logger.error(e.getMessage(), e);
+ }
+
+ if (responseResult != null) {
+ return responseResult;
+ }
+
+ try {
+ return new TextBuilder().build("感谢关注", wxMessage, weixinService);
+ } catch (Exception e) {
+ this.logger.error(e.getMessage(), e);
+ }
+
+ return null;
+ }
+
+ /**
+ * 处理特殊请求,比如如果是扫码进来的,可以做相应处理
+ */
+ private WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage)
+ throws Exception {
+ //TODO
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/vertical/wx/mp/handler/UnsubscribeHandler.java b/src/main/java/com/rymcu/vertical/wx/mp/handler/UnsubscribeHandler.java
new file mode 100644
index 0000000..49cfa3d
--- /dev/null
+++ b/src/main/java/com/rymcu/vertical/wx/mp/handler/UnsubscribeHandler.java
@@ -0,0 +1,27 @@
+package com.rymcu.vertical.wx.mp.handler;
+
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @author Binary Wang(https://github.com/binarywang)
+ */
+@Component
+public class UnsubscribeHandler extends AbstractHandler {
+
+ @Override
+ public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+ Map context, WxMpService wxMpService,
+ WxSessionManager sessionManager) {
+ String openId = wxMessage.getFromUser();
+ this.logger.info("取消关注用户 OPENID: " + openId);
+ // TODO 可以更新本地数据库为取消关注状态
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/rymcu/vertical/wx/mp/utils/JsonUtils.java b/src/main/java/com/rymcu/vertical/wx/mp/utils/JsonUtils.java
new file mode 100644
index 0000000..bda28aa
--- /dev/null
+++ b/src/main/java/com/rymcu/vertical/wx/mp/utils/JsonUtils.java
@@ -0,0 +1,9 @@
+package com.rymcu.vertical.wx.mp.utils;
+
+import com.alibaba.fastjson.JSONObject;
+
+public class JsonUtils {
+ public static String toJson(Object obj) {
+ return JSONObject.toJSONString(obj);
+ }
+}