lijilei 3 лет назад
Родитель
Сommit
ae55b20182
19 измененных файлов с 796 добавлено и 1 удалено
  1. 19 1
      book-push/pom.xml
  2. 4 0
      book-push/src/main/java/com/book/push/Application.java
  3. 17 0
      book-push/src/main/java/com/book/push/builder/AbstractBuilder.java
  4. 24 0
      book-push/src/main/java/com/book/push/builder/ImageBuilder.java
  5. 22 0
      book-push/src/main/java/com/book/push/builder/TextBuilder.java
  6. 188 0
      book-push/src/main/java/com/book/push/controller/WxMenuController.java
  7. 107 0
      book-push/src/main/java/com/book/push/controller/WxPortalController.java
  8. 47 0
      book-push/src/main/java/com/book/push/controller/WxRedirectController.java
  9. 12 0
      book-push/src/main/java/com/book/push/handler/AbstractHandler.java
  10. 25 0
      book-push/src/main/java/com/book/push/handler/KfSessionHandler.java
  11. 44 0
      book-push/src/main/java/com/book/push/handler/LocationHandler.java
  12. 27 0
      book-push/src/main/java/com/book/push/handler/LogHandler.java
  13. 35 0
      book-push/src/main/java/com/book/push/handler/MenuHandler.java
  14. 53 0
      book-push/src/main/java/com/book/push/handler/MsgHandler.java
  15. 24 0
      book-push/src/main/java/com/book/push/handler/NullHandler.java
  16. 24 0
      book-push/src/main/java/com/book/push/handler/ScanHandler.java
  17. 27 0
      book-push/src/main/java/com/book/push/handler/StoreCheckNotifyHandler.java
  18. 70 0
      book-push/src/main/java/com/book/push/handler/SubscribeHandler.java
  19. 27 0
      book-push/src/main/java/com/book/push/handler/UnsubscribeHandler.java

+ 19 - 1
book-push/pom.xml

@@ -64,6 +64,10 @@
                     <groupId>org.springframework.boot</groupId>
                     <artifactId>spring-boot-starter-logging</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>com.fasterxml.jackson.core</groupId>
+                    <artifactId>jackson-databind</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
         <dependency>
@@ -92,7 +96,11 @@
             <artifactId>disruptor</artifactId>
             <version>3.3.7</version>
         </dependency>
-
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
 
         <!-- lombok -->
         <dependency>
@@ -100,6 +108,16 @@
             <artifactId>lombok</artifactId>
             <version>1.18.4</version>
         </dependency>
+        <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>wx-java-mp-spring-boot-starter</artifactId>
+            <version>4.1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.75</version>
+        </dependency>
 
     </dependencies>
 </project>

+ 4 - 0
book-push/src/main/java/com/book/push/Application.java

@@ -3,6 +3,10 @@ package com.book.push;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 
+
+/**
+ * @author win7
+ */
 @SpringBootApplication
 public class Application {
     public static void main(String[] args) {

+ 17 - 0
book-push/src/main/java/com/book/push/builder/AbstractBuilder.java

@@ -0,0 +1,17 @@
+package com.book.push.builder;
+
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author
+ */
+public abstract class AbstractBuilder {
+    protected final Logger logger = LoggerFactory.getLogger(getClass());
+
+    public abstract WxMpXmlOutMessage build(String content,
+                                            WxMpXmlMessage wxMessage, WxMpService service);
+}

+ 24 - 0
book-push/src/main/java/com/book/push/builder/ImageBuilder.java

@@ -0,0 +1,24 @@
+package com.book.push.builder;
+
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutImageMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+
+/**
+ * @author
+ */
+public class ImageBuilder extends AbstractBuilder {
+
+    @Override
+    public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage,
+                                   WxMpService service) {
+
+        WxMpXmlOutImageMessage m = WxMpXmlOutMessage.IMAGE().mediaId(content)
+            .fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
+            .build();
+
+        return m;
+    }
+
+}

+ 22 - 0
book-push/src/main/java/com/book/push/builder/TextBuilder.java

@@ -0,0 +1,22 @@
+package com.book.push.builder;
+
+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.message.WxMpXmlOutTextMessage;
+
+/**
+ * @author
+ */
+public class TextBuilder extends AbstractBuilder {
+
+    @Override
+    public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage,
+                                   WxMpService service) {
+        WxMpXmlOutTextMessage m = WxMpXmlOutMessage.TEXT().content(content)
+            .fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
+            .build();
+        return m;
+    }
+
+}

+ 188 - 0
book-push/src/main/java/com/book/push/controller/WxMenuController.java

@@ -0,0 +1,188 @@
+package com.book.push.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
+ */
+@AllArgsConstructor
+@RestController
+@RequestMapping("/wx/menu/{appid}")
+public class WxMenuController {
+    private final WxMpService wxService;
+
+    /**
+     * <pre>
+     * 自定义菜单创建接口
+     * 详情请见: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
+     * </pre>
+     *
+     * @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).getOAuth2Service().buildAuthorizationUrl(
+                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);
+    }
+
+    /**
+     * <pre>
+     * 自定义菜单创建接口
+     * 详情请见: 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
+     * </pre>
+     *
+     * @return 如果是个性化菜单,则返回menuid,否则返回null
+     */
+    @PostMapping("/createByJson")
+    public String menuCreate(@PathVariable String appid, @RequestBody String json) throws WxErrorException {
+        return this.wxService.switchoverTo(appid).getMenuService().menuCreate(json);
+    }
+
+    /**
+     * <pre>
+     * 自定义菜单删除接口
+     * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141015&token=&lang=zh_CN
+     * </pre>
+     */
+    @GetMapping("/delete")
+    public void menuDelete(@PathVariable String appid) throws WxErrorException {
+        this.wxService.switchoverTo(appid).getMenuService().menuDelete();
+    }
+
+    /**
+     * <pre>
+     * 删除个性化菜单接口
+     * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
+     * </pre>
+     *
+     * @param menuId 个性化菜单的menuid
+     */
+    @GetMapping("/delete/{menuId}")
+    public void menuDelete(@PathVariable String appid, @PathVariable String menuId) throws WxErrorException {
+        this.wxService.switchoverTo(appid).getMenuService().menuDelete(menuId);
+    }
+
+    /**
+     * <pre>
+     * 自定义菜单查询接口
+     * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141014&token=&lang=zh_CN
+     * </pre>
+     */
+    @GetMapping("/get")
+    public WxMpMenu menuGet(@PathVariable String appid) throws WxErrorException {
+        return this.wxService.switchoverTo(appid).getMenuService().menuGet();
+    }
+
+    /**
+     * <pre>
+     * 测试个性化菜单匹配结果
+     * 详情请见: http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
+     * </pre>
+     *
+     * @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);
+    }
+
+    /**
+     * <pre>
+     * 获取自定义菜单配置接口
+     * 本接口将会提供公众号当前使用的自定义菜单的配置,如果公众号是通过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
+     * </pre>
+     */
+    @GetMapping("/getSelfMenuInfo")
+    public WxMpGetSelfMenuInfoResult getSelfMenuInfo(@PathVariable String appid) throws WxErrorException {
+        return this.wxService.switchoverTo(appid).getMenuService().getSelfMenuInfo();
+    }
+}

+ 107 - 0
book-push/src/main/java/com/book/push/controller/WxPortalController.java

@@ -0,0 +1,107 @@
+package com.book.push.controller;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.mp.api.WxMpMessageRouter;
+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.web.bind.annotation.*;
+
+/**
+ *
+ * 微信认证
+ * @author
+ */
+@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;
+    }
+
+}

+ 47 - 0
book-push/src/main/java/com/book/push/controller/WxRedirectController.java

@@ -0,0 +1,47 @@
+package com.book.push.controller;
+
+import lombok.AllArgsConstructor;
+import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
+import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.mp.api.WxMpService;
+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;
+
+/**
+ * @author win7
+ */
+@AllArgsConstructor
+@Controller
+@RequestMapping("/wx/redirect/{appid}")
+public class WxRedirectController {
+    private final WxMpService wxService;
+
+
+    /**
+     * 接收微信静默授权,获取用户信息
+     * @param appid
+     * @param code
+     * @param map
+     * @return
+     */
+    @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 {
+            WxOAuth2AccessToken accessToken = wxService.getOAuth2Service().getAccessToken(code);
+            WxOAuth2UserInfo user = wxService.getOAuth2Service().getUserInfo(accessToken, null);
+            map.put("user", user);
+        } catch (WxErrorException e) {
+            e.printStackTrace();
+        }
+
+        return "greet_user";
+    }
+}

+ 12 - 0
book-push/src/main/java/com/book/push/handler/AbstractHandler.java

@@ -0,0 +1,12 @@
+package com.book.push.handler;
+
+import me.chanjar.weixin.mp.api.WxMpMessageHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author
+ */
+public abstract class AbstractHandler implements WxMpMessageHandler {
+    protected Logger logger = LoggerFactory.getLogger(getClass());
+}

+ 25 - 0
book-push/src/main/java/com/book/push/handler/KfSessionHandler.java

@@ -0,0 +1,25 @@
+package com.book.push.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
+ */
+@Component
+public class KfSessionHandler extends AbstractHandler {
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> context, WxMpService wxMpService,
+                                    WxSessionManager sessionManager) {
+        //TODO 对会话做处理
+        return null;
+    }
+
+}

+ 44 - 0
book-push/src/main/java/com/book/push/handler/LocationHandler.java

@@ -0,0 +1,44 @@
+package com.book.push.handler;
+
+import com.book.push.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
+ */
+@Component
+public class LocationHandler extends AbstractHandler {
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> 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;
+    }
+
+}

+ 27 - 0
book-push/src/main/java/com/book/push/handler/LogHandler.java

@@ -0,0 +1,27 @@
+package com.book.push.handler;
+
+import com.alibaba.fastjson.JSON;
+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
+ */
+@Component
+public class LogHandler extends AbstractHandler {
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> context, WxMpService wxMpService,
+                                    WxSessionManager sessionManager) {
+        this.logger.info("\n接收到请求消息,内容:{}", JSON.toJSONString(wxMessage));
+        return null;
+    }
+
+}

+ 35 - 0
book-push/src/main/java/com/book/push/handler/MenuHandler.java

@@ -0,0 +1,35 @@
+package com.book.push.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
+ */
+@Component
+public class MenuHandler extends AbstractHandler {
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> 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();
+    }
+
+}

+ 53 - 0
book-push/src/main/java/com/book/push/handler/MsgHandler.java

@@ -0,0 +1,53 @@
+package com.book.push.handler;
+
+import com.alibaba.fastjson.JSON;
+import com.book.push.builder.TextBuilder;
+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.apache.logging.log4j.core.util.JsonUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
+
+/**
+ * @author
+ */
+@Component
+public class MsgHandler extends AbstractHandler {
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> 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 = "收到信息内容:" + JSON.toJSONString(wxMessage);
+
+        return new TextBuilder().build(content, wxMessage, weixinService);
+
+    }
+
+}

+ 24 - 0
book-push/src/main/java/com/book/push/handler/NullHandler.java

@@ -0,0 +1,24 @@
+package com.book.push.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
+ */
+@Component
+public class NullHandler extends AbstractHandler {
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> context, WxMpService wxMpService,
+                                    WxSessionManager sessionManager) {
+        return null;
+    }
+
+}

+ 24 - 0
book-push/src/main/java/com/book/push/handler/ScanHandler.java

@@ -0,0 +1,24 @@
+package com.book.push.handler;
+
+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.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @author
+ */
+@Component
+public class ScanHandler extends AbstractHandler {
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMpXmlMessage, Map<String, Object> map,
+                                    WxMpService wxMpService, WxSessionManager wxSessionManager) throws WxErrorException {
+        // 扫码事件处理
+        return null;
+    }
+}

+ 27 - 0
book-push/src/main/java/com/book/push/handler/StoreCheckNotifyHandler.java

@@ -0,0 +1,27 @@
+package com.book.push.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
+ */
+@Component
+public class StoreCheckNotifyHandler extends AbstractHandler {
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> context, WxMpService wxMpService,
+                                    WxSessionManager sessionManager) {
+        // TODO 处理门店审核事件
+        return null;
+    }
+
+}

+ 70 - 0
book-push/src/main/java/com/book/push/handler/SubscribeHandler.java

@@ -0,0 +1,70 @@
+package com.book.push.handler;
+
+import com.book.push.builder.TextBuilder;
+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;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @author
+ */
+@Component
+public class SubscribeHandler extends AbstractHandler {
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> 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;
+    }
+
+}

+ 27 - 0
book-push/src/main/java/com/book/push/handler/UnsubscribeHandler.java

@@ -0,0 +1,27 @@
+package com.book.push.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
+ */
+@Component
+public class UnsubscribeHandler extends AbstractHandler {
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> context, WxMpService wxMpService,
+                                    WxSessionManager sessionManager) {
+        String openId = wxMessage.getFromUser();
+        this.logger.info("取消关注用户 OPENID: " + openId);
+        // TODO 可以更新本地数据库为取消关注状态
+        return null;
+    }
+
+}