SpringCloud : 接入 微信公众号平台(一)、接入微信请求(支持多公众号)

Maven:

Feign 版本10.1.0

Spring 版本 5.1.5.RELEASE

SpringBoot 版本 2.1.5.RELEASE

SpringCloud 版本 2.1.1.RELEASE

Weixin-java 版本 3.7.0,链接

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.60</version>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>
<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-mp</artifactId>
    <version>3.7.0</version>
</dependency>

公共网关接口: https://你的域名/gate/微信公众号appId

其中 validAuth 方法负责校验签名,微信服务器会发送一个 普通的GET请求,命中该方法处理。

msgForward 方法负责消息的转发,微信服务器会发送一个xml协议的POST请求,命中该方法。

消息的加解密参考:MP_消息的加解密 ,更多使用技巧

消息路由:MP_微信消息路由器

源码参考:WxPortalController.java 。

import com.phpdragon.wechat.proxy.config.WeChatConfig;
import com.phpdragon.wechat.proxy.config.WechatEventConfig;
import com.phpdragon.wechat.proxy.handler.EventHandler;
import com.phpdragon.wechat.proxy.handler.LogHandler;
import com.phpdragon.wechat.proxy.handler.MsgHandler;
import com.phpdragon.wechat.proxy.handler.TplMsgFeedbackHandler;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
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 me.chanjar.weixin.mp.util.crypto.WxMpCryptUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.*;

import java.util.Objects;

/**
 * 参考:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html
 */
@Slf4j
@RestController
@RequestMapping("/gate/")
public class GateController {

    @Autowired
    private WeChatConfig weChatConfig;
    @Autowired
    private LogHandler logHandler;
    @Autowired
    private EventHandler eventHandler;
    @Autowired
    private TplMsgFeedbackHandler tplMsgFeedbackHandler;
    @Autowired
    private MsgHandler msgHandler;

    /**
     * 微信验签
     *
     * @param signature
     * @param timestamp
     * @param nonce
     * @param echostr
     * @return
     */
    @ResponseBody
    @GetMapping(value = "/{app_id}", produces = "text/plain;charset=utf-8")
    public String validAuth(@PathVariable("app_id") 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("接收到来自微信服务器的认证请求:[appId:{},{}, {}, {}, {}]", appId, signature, timestamp, nonce, echostr);

        if (StringUtils.isAnyBlank(appId, signature, timestamp, nonce, echostr)) {
            throw new IllegalArgumentException("请求参数非法!");
        }

        WxMpService wxMpService = weChatConfig.getWxMpService(appId);
        if (wxMpService.checkSignature(timestamp, nonce, signature)) {
            return echostr;
        }

        return "请求非法";
    }

    /**
     * 消息转发---中转站
     * 每次微信端的消息都会来到这里进行分发
     * 对微信公众号相关的一些动作,都以报文形式推送到该接口,
     * 根据请求的类型,进行路由分发处理
     */
    @PostMapping(value = "/{app_id}", produces = "application/xml; charset=UTF-8")
    public String msgForward(@PathVariable("app_id") String appId,
                             @RequestParam(name = "encrypt_type", required = false) String encryptType,
                             @RequestParam(name = "signature", required = false) String signature,
                             @RequestParam(name = "timestamp", required = false) String timestamp,
                             @RequestParam(name = "nonce", required = false) String nonce,
                             @RequestParam(name = "msg_signature", required = false) String msgSignature,
                             @RequestBody String requestBody) {
        log.info("接收微信服务器请求:[signature=[{}], encType=[{}], msgSignature=[{}]," + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
                signature, encryptType, msgSignature, timestamp, nonce, requestBody);

        String outMsg = "";
        try {
            outMsg = this.handleMsg(appId, encryptType, signature, timestamp, nonce, msgSignature, requestBody);
            log.info("返回响应消息,outMsg:\n{}", outMsg);
        } catch (Exception e) {
            log.error("响应请求异常,error:{},{}", e.getMessage(), e);
        }

        return outMsg;
    }

    /**
     * 处理消息的入口
     *
     * @param appId
     * @param signature
     * @param encryptType
     * @param msgSignature
     * @param timestamp
     * @param nonce
     * @param requestBody
     * @return
     */
    @Nullable
    private String handleMsg(String appId, String encryptType, String signature, String timestamp, String nonce, String msgSignature, String requestBody) {
        WxMpService wxMpService = weChatConfig.getWxMpService(appId);

        if ("aes".equals(encryptType)) {
            if (!wxMpService.checkSignature(timestamp, nonce, signature)) {
                throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
            }
        }

        boolean isEncrypt = "aes".equals(encryptType);

        WxMpXmlMessage inMessage;
        if (isEncrypt) {
            inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxMpService.getWxMpConfigStorage(), timestamp, nonce, msgSignature);
        } else {
            inMessage = WxMpXmlMessage.fromXml(requestBody);
        }

        WxMpXmlOutMessage outMessage = this.buildMsgRouter(wxMpService).route(inMessage);
        if (Objects.isNull(outMessage)) {
            return "";
        }

        String outMsg = outMessage.toXml();

        if (isEncrypt) {
            WxMpCryptUtil cryptUtil = new WxMpCryptUtil(wxMpService.getWxMpConfigStorage());
            outMsg = cryptUtil.encrypt(outMsg);
        }

        return outMsg;
    }

    /**
     * 构造消息路由处理器
     *
     * @param wxMpService
     */
    private WxMpMessageRouter buildMsgRouter(final WxMpService wxMpService) {
        final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);
        // 记录所有事件的日志
        newRouter.rule().handler(this.logHandler).next();
        // 处理事件请求
        for (String eventKey : WechatEventConfig.ALL_EVENTS) {
            newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
                    .event(eventKey).handler(this.eventHandler)
                    .end();
        }
        //处理模版消息的发送反馈
        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
                .event(WxConsts.EventType.TEMPLATE_SEND_JOB_FINISH)
                .handler(this.tplMsgFeedbackHandler)
                .end();
        // 默认,转发消息给客服人员
        newRouter.rule().async(false).handler(this.msgHandler).end();
        return newRouter;
    }
}

LogHandler:

import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpMessageHandler;
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;

/**
 * 对所有接收到的消息输出日志,也可进行持久化处理
 * <p>
 * Created by FirenzesEagle on 2016/7/27 0027.
 * Email:[email protected]
 */
@Slf4j
@Component
public class LogHandler implements WxMpMessageHandler {

    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
                                    Map<String, Object> context, WxMpService wxMpService,
                                    WxSessionManager sessionManager) {

        //TODO: 保存消息日志
        //wXLogService.doSaveReceiveLog(inMessage);

        log.info("\n接收到事件请求,内容:【{}】", wxMessage.toString());

        return null;
    }
}

TplMsgFeedbackHandler:

import com.phpdragon.wechat.proxy.logic.MsgTplLogic;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpMessageHandler;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * 处理事件
 */
@Slf4j
@Component
public class TplMsgFeedbackHandler implements WxMpMessageHandler {

    @Autowired
    private MsgTplLogic msgTplLogic;

    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> map, WxMpService wxMpService, WxSessionManager wxSessionManager) throws WxErrorException {
        msgTplLogic.updateLog(wxMessage);
        return null;
    }
}

MsgHandler:

import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpMessageHandler;
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;

/**
 * 处理客户消息
 */
@Slf4j
@Component
public class MsgHandler implements WxMpMessageHandler {
    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService,
                                    WxSessionManager sessionManager) {
        return WxMpXmlOutMessage.TEXT().fromUser(wxMessage.getToUser())
                .toUser(wxMessage.getFromUser()).content("您好,正在处理您的请求").build();
        //转发给客服
//        return WxMpXmlOutMessage
//            .TRANSFER_CUSTOMER_SERVICE().fromUser(wxMessage.getToUser())
//            .toUser(wxMessage.getFromUser()).build();
    }
}

EventHandler:

import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpMessageHandler;
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;

/**
 * 处理事件
 */
@Slf4j
@Component
public class EventHandler implements WxMpMessageHandler {

    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService,
                                    WxSessionManager sessionManager) {
        return WxMpXmlOutMessage.TEXT().fromUser(wxMessage.getToUser())
                .toUser(wxMessage.getFromUser()).content("您好,正在处理您的请求").build();
    }
}

WeChatConfig:

import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;

@Configuration
public class WeChatConfig {

    //TODO: 你的域名
    public static final String CURRENT_HOST = "你的域名";

    @Autowired
    private JedisPool jedisPool;

    /**
     * 取mp SDK
     *
     * @param appId
     * @return
     */
    public WxMpService getWxMpService(String appId) {
        WxMpRedisConfigImpl mpConfig = new WxMpRedisConfigImpl(jedisPool);
        //TODO: 用数据库进行保存
        mpConfig.setAppId("微信ID");
        mpConfig.setSecret("微信密钥");
        mpConfig.setToken("微信通讯token");
        mpConfig.setAesKey("加密密钥");

        WxMpService wxMpService = new WxMpServiceImpl();
        wxMpService.setWxMpConfigStorage(mpConfig);
        return wxMpService;
    }
}

接入到此完毕,使用官方推荐工具调试一下看看是否可通,微信公众平台接口调试工具!。

PS:

公众号开发文档wiki

Java开发微信公众号之整合weixin-java-tools框架开发微信公众号

从零实现 Spring Boot 2.0 整合 weixin-java-mp(weixin-java-tools) 获取 openId,用于微信授权

Demo 列表

  1. 微信支付 Demo:GitHub码云
  2. 企业号/企业微信 Demo:GitHub码云
  3. 微信小程序 Demo:GitHub码云
  4. 开放平台 Demo:GitHub码云
  5. 公众号 Demo:
    • 使用 Spring MVC 实现的公众号 Demo:GitHub码云
    • 使用 Spring Boot 实现的公众号 Demo(支持多公众号):GitHub码云
    • 含公众号和部分微信支付代码的 Demo:GitHub码云

原文地址:https://www.cnblogs.com/phpdragon/p/12193495.html

时间: 2024-11-06 07:20:55

SpringCloud : 接入 微信公众号平台(一)、接入微信请求(支持多公众号)的相关文章

微信公众号平台接口开发:基础支持,获取access_token

新建Asp.net MVC 4.0项目 WeChatSubscript是项目UI层 WeChatTools是封装操作访问公众号接口的一些方法类库 获取AccssToken 我们要的得到AccessToken,这是所有接口访问的基础,我们看看官方给出的接口调用文档 很简单明了,grant_type=client_credential,这是固定的不会变 appid与secret就是前面一章我叫大家记起来的那个认证口令数据. 下边我们来实现这个功能,新建WeCharBase.cs 1 public c

微信公众号平台接口开发:基础支持,获取微信服务器IP地址

官方说明 目前看不出来这个接口有哪些具体运用,但是既然有这个接口,那我们就试试能不能用 访问接口 修改WeCharBase.cs,新增以下2个方法 1 public static string ServerIPs 2 { 3 get { return GetServerIPs(); } 4 } 5 6 /// <summary>获取所有服务器IP</summary> 7 /// <returns></returns> 8 private static str

微信发廊预约平台开发

微信发廊预约平台系统(陈琦:138-2848-7919可微)微信发廊预约平台开发,微信发廊预约平台定制,微信发廊预约平台软件,微信发廊预约平台模式,微信发廊预约平台APP,微信发廊预约平台后台,微信发廊预约平台管理,微信发廊预约平台PC端,微信发廊预约平台商城. 微信发廊预约平台的功能 1.预约时间随时随地 只要用户拥有网络,随时随地可以在微信发廊预约平台选择自己喜欢的时间预约微信发廊美发美甲师. 2.自动定位 平台能够自动定位到用户所在的位置以及微信发廊师所在的那家微信发廊店的位置. 3.微信

SpringCloud : 接入 微信公众号平台(三)、获取JsSDK配置参数

Java: import com.phpdragon.wechat.proxy.config.WeChatConfig; import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.bean.WxJsapiSignature; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService;

SpringCloud : 接入 微信公众号平台(四)、获取微信用户信息接口

代码参考: import com.phpdragon.wechat.proxy.config.WeChatConfig; import com.phpdragon.wechat.proxy.dto.mp.user.GetOauthUserInfoDto; import com.phpdragon.wechat.proxy.dto.mp.user.GetOpenidDto; import com.phpdragon.wechat.proxy.dto.mp.user.GetUserInfoDto;

[转载红鱼儿]delphi 实现微信开发(2)接入微信公众号平台

先要学习一下接入的资料,在这里,因为原理都在,所以一定要认真阅读,然后,利用Delphi实现一个对应函数: function CheckSignature(const signature, timestamp, nonce, token: string): boolean; var strs: TStringList;   tmpStr: string; begin strs := TStringList.Create;   try     strs.Add(token);     strs.A

网络架构、云平台和微信公众平台开发接入

版权声明:本文为博主原创文章,未经博主允许不得转载. 云与后端相关的技术似乎并不属于嵌入式和物联智能硬件开发工程师的范畴,但是嵌入式开发工程师有必要认识成熟的网络架构和相关的云技术,以拓展自己在系统架构方面的视野.大数据分析是物联网背后的核心价值,物联智能硬件是物联大系统的终端,开发工程师不仅要深入精通物联技术,也应该去理解大系统,甚至整个生态领域的相关技术. 作为嵌入式开发工程师,也许并不需要熟悉云和后端的技术开发,但至少要对其中用到的技术和接口有一定的认识. 一.网络架构 常见的网络架构分为

20160170002 微信公众平台开发接入指南

参考地址: http://mp.weixin.qq.com/wiki/17/2d4265491f12608cd170a95559800f2d.html 接入指南 目录 1 概述 2 第一步:填写服务器配置 3 第二步:验证服务器地址的有效性 4 第三步:依据接口文档实现业务逻辑 概述 接入微信公众平台开发,开发者需要按照如下步骤完成: 1.填写服务器配置 2.验证服务器地址的有效性 3.依据接口文档实现业务逻辑 下面详细介绍这3个步骤. 第一步:填写服务器配置 登录微信公众平台官网后,在公众平台

一、微信公众平台的接入微信公众平台的接入

一.微信公众平台的接入微信公众平台的接入 1.官方文档 2.设置公司或者个人服务器网站: 要接入微信,我们要建立个人网站去接收微信数据,并返回相应格式的数据,我们需要建立一个能够让外网访问的网站,并按照官方文档要求建立一个一般处理程序用来接收微信发送的数据(signature,timestamp,nonce,echostr),在服务器上验证之后,返回微信要求的数据(echostr),一般处理程序代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18