微信商城开源版二次开发(二)

最近想理解如何Java对接微信平台,疾速搭建残缺我的项目开发,发现网上有很对开源的这类二开源码。https://gitee.com/luozijing12...就是其中一个,介绍能够关上网页自行查看,上面介绍了该我的项目如何对接微信公众号和部署。

上面是我本人在云服务器上利用docker疾速部署的http://81.69.254.72/index。 体验账户: admin/admin123

SKD中接发微信公众号音讯的路由模式

微信公众号会有许多不同类型的音讯,有文本、图片、天文等等,为了更好的辨别不同音讯的解决,JAVA 微信开源包-- https://github.com/Wechat-Gro... 利用路由模式来解决。

首先业务代码包里注入路由器 和wxMpService(http告诉解决类)

 @Bean    public WxMpMessageRouter messageRouter(WxMpService wxMpService) {        final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);        // 记录所有事件的日志 (异步同步执行属性)        newRouter.rule().handler(this.logHandler).next();        // 接管客服会话治理事件 handler可放进List多个解决        newRouter.rule().async(false).msgType(EVENT).event(KF_CREATE_SESSION)                .handler(this.kfSessionHandler).end();        newRouter.rule().async(false).msgType(EVENT).event(KF_CLOSE_SESSION)                .handler(this.kfSessionHandler).end();        newRouter.rule().async(false).msgType(EVENT).event(KF_SWITCH_SESSION)                .handler(this.kfSessionHandler).end();        //......    }

异步和同步执行形式,满足不同业务属性,如有些数据须要异步同步给其余业务侧,就可用异步解决形式,这里的异步解决用来双线程,一个线程异步执行,一个线程异步期待,不便知悉后果,也晋升了代码可靠性

WxMpXmlOutMessage res = null;final List<Future<?>> futures = new ArrayList();Iterator var8 = matchRules.iterator();while(var8.hasNext()) {    final WxMpMessageRouterRule rule = (WxMpMessageRouterRule)var8.next();    if (rule.isAsync()) {        // 线程池异步执行,futruesTask封装后果        futures.add(this.executorService.submit(new Runnable() {            public void run() {                rule.service(wxMessage, context, mpService, WxMpMessageRouter.this.sessionManager, WxMpMessageRouter.this.exceptionHandler);            }        }));    } else {        // 同步执行,进入上面的handler和切面解决        res = rule.service(wxMessage, context, mpService, this.sessionManager, this.exceptionHandler);        this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUser());        this.sessionEndAccess(wxMessage);    }} // 有异步工作每,异步获取后果,判断异步是否实现if (futures.size() > 0) {    this.executorService.submit(new Runnable() {        public void run() {            Iterator var1 = futures.iterator();            while(var1.hasNext()) {                Future future = (Future)var1.next();                                try {                    future.get();                    WxMpMessageRouter.this.log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUser());                    WxMpMessageRouter.this.sessionEndAccess(wxMessage);                    // 对异样的解决                } catch (InterruptedException var4) {                    WxMpMessageRouter.this.log.error("Error happened when wait task finish", var4);                    Thread.currentThread().interrupt();                } catch (ExecutionException var5) {                    WxMpMessageRouter.this.log.error("Error happened when wait task finish", var5);                }            }        }    });}

举例子, wx文本音讯进入对应后路由解决

   try {            Iterator var6 = this.interceptors.iterator();            // 路由拦截器数组 也是自定义,不便拓展性能,这里并未用到            WxMpMessageInterceptor interceptor;            do {                if (!var6.hasNext()) {                    WxMpXmlOutMessage res = null;                    Iterator var11 = this.handlers.iterator();                    while(var11.hasNext()) {                        WxMpMessageHandler handler = (WxMpMessageHandler)var11.next();                        if (handler != null) {                            // 上述定义的路由处理器数组                            res = handler.handle(wxMessage, (Map)context, wxMpService, sessionManager);                        }                    }                    return res;                }                interceptor = (WxMpMessageInterceptor)var6.next();                // 先执行拦截器业务            } while(interceptor.intercept(wxMessage, (Map)context, wxMpService, sessionManager));            return null;        } catch (WxErrorException var9) {            exceptionHandler.handle(var9);            return null;        }

初始化中具体的handler业务,在网页配置页面配置好如何进行主动回复音讯,有半匹配和全匹配两种,也有图片\语音\语音等,这些数据是存储在微信云端.具体能够扫描本零碎绑定的公众号,在页面中主动配置http://81.69.254.72/wxmp/wxau...进行尝试.

@Overridepublic WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,                                Map<String, Object> context, WxMpService wxMpService,                                WxSessionManager sessionManager) {    //组装回复音讯    if (!wxMessage.getMsgType().equals(XmlMsgType.EVENT)) {        WxMpXmlOutMessage rs;        //TODO 能够抉择将音讯保留到本地        WxUser wxUser = wxUserMapper.selectOne(Wrappers.<WxUser>lambdaQuery()                .eq(WxUser::getOpenId,wxMessage.getFromUser()));        if(WxConsts.KefuMsgType.TEXT.equals(wxMessage.getMsgType())){//1、先解决是否有文本关键字回复            //先全匹配 网页中设置的主动全匹配服务,能够关上网页本人操作试试 http://81.69.254.72/wxmp/wxautoreply            List<WxAutoReply> listWxAutoReply = wxAutoReplyService.list(Wrappers                    .<WxAutoReply>query().lambda()                    .eq(WxAutoReply::getType, ConfigConstant.WX_AUTO_REPLY_TYPE_3)                    .eq(WxAutoReply::getRepMate, ConfigConstant.WX_REP_MATE_1)                    .eq(WxAutoReply::getReqKey, wxMessage.getContent()));            if(listWxAutoReply!=null && listWxAutoReply.size()>0){                rs = this.getWxMpXmlOutMessage(wxMessage,listWxAutoReply,wxUser,wxMsgService);                if(rs != null){                    return  rs;                }            }            //再半匹配            listWxAutoReply = wxAutoReplyService.list(Wrappers                    .<WxAutoReply>query().lambda()                    .eq(WxAutoReply::getType, ConfigConstant.WX_AUTO_REPLY_TYPE_3)                    .eq(WxAutoReply::getRepMate, ConfigConstant.WX_REP_MATE_2)                    .like(WxAutoReply::getReqKey, wxMessage.getContent()));            if(listWxAutoReply!=null && listWxAutoReply.size()>0) {                rs = this.getWxMpXmlOutMessage(wxMessage, listWxAutoReply, wxUser,wxMsgService);                if (rs != null) {                    return rs;                }            }        }        //2、再解决音讯回复        List<WxAutoReply> listWxAutoReply = wxAutoReplyService.list(Wrappers                .<WxAutoReply>query().lambda()                .eq(WxAutoReply::getType, ConfigConstant.WX_AUTO_REPLY_TYPE_2)                .eq(WxAutoReply::getReqType, wxMessage.getMsgType()));        rs = this.getWxMpXmlOutMessage(wxMessage,listWxAutoReply,wxUser,wxMsgService);        return rs;    }    return null;}

微信公众号token校验

小程序交互时是通过token来进行验证用户是否登录小程序,因而每次交互须要校验用户登录有效性, 实际上通过微信获取登录的用户信息吗,获取后存入redis的过期来校验用户是否生效,这是通用性的解决方案,也有不足之处,就是session超时不好管制,影响体验.

  //session过期后申请微信获取用户信息 而后存入redis 设置过期工夫  public WxMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws WxErrorException {        WxMaConfig config = this.getWxMaConfig();        Map<String, String> params = new HashMap(8);        params.put("appid", config.getAppid());        params.put("secret", config.getSecret());        params.put("js_code", jsCode);        params.put("grant_type", "authorization_code");        String result = this.get("https://api.weixin.qq.com/sns/jscode2session", Joiner.on("&").withKeyValueSeparator("=").join(params));        return WxMaJscode2SessionResult.fromJson(result);    }

spring security拦截器校验session有效性

@Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {        //获取header中的thirdSession        String thirdSessionHeader = request.getHeader(ConfigConstant.HEADER_THIRDSESSION);        if(StrUtil.isNotBlank(thirdSessionHeader)){            //获取缓存中的ThirdSession            String key = WxMaConstants.THIRD_SESSION_BEGIN  + ":" + thirdSessionHeader;            Object thirdSessionObj = redisTemplate.opsForValue().get(key);            if(thirdSessionObj == null) {//session过期                AjaxResult r = AjaxResult.error(MyReturnCode.ERR_60001.getCode(), MyReturnCode.ERR_60001.getMsg());                this.writerPrint(response, r);                return Boolean.FALSE;            }else {                String thirdSessionStr = String.valueOf(thirdSessionObj);                ThirdSession thirdSession = JSONUtil.toBean(thirdSessionStr, ThirdSession.class);                ThirdSessionHolder.setThirdSession(thirdSession);//设置thirdSession            }        }else{            AjaxResult r = AjaxResult.error(MyReturnCode.ERR_60002.getCode(), MyReturnCode.ERR_60002.getMsg());            this.writerPrint(response, r);            return Boolean.FALSE;        }        return Boolean.TRUE;    }    private void writerPrint(HttpServletResponse response, AjaxResult r) throws IOException {        //返回超时错误码,触发小程序从新登录        response.setCharacterEncoding(CommonConstants.UTF8);        response.setContentType(MediaType.APPLICATION_JSON_VALUE);        PrintWriter writer = response.getWriter();        writer.print(JSONUtil.parseObj(r));        if(writer != null){            writer.close();        }    }