微信开放平台第三方授权(第三篇)-获取auth_access_token

1.AuthAcsessToken的获取

继续上文,上文提到了想要发送消息,就要获取授权单独的authtoken,通过这个token才能调用微信发送消息接口。有六个步骤,少一步也获取不到这个authaccesstoken。

Token生成说明 | 微信开放文档

这里需要注意的是:

weixin-java-open没有实现消息发送,就要结合
weixin-java-mp使用,才能实现发送消息。

weixin-java-mp-demo: 基于Spring Boot 和 WxJava 实现的微信公众号Java后端Demo,支持多公众号

 

我们看最后一步,获取token需要的参数

2.代码部分

 service

package com.test.wechat.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.test.sdk.service.impl.ImServiceImpl;
import com.test.wechat.config.WechatOpenConfigStorage;
import com.test.wechat.config.WechatOpenProperties;
import com.test.wechat.handler.*;
import com.test.wechat.util.HttpClientUtil;
import com.test.wechat.consts.WechatOpenConst;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.open.api.WxOpenComponentService;
import me.chanjar.weixin.open.api.impl.WxOpenMessageRouter;
import me.chanjar.weixin.open.api.impl.WxOpenServiceImpl;
import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

/**
 * @ClassName WechatOpenService
 * @Description TODO
 * @Author Jiangnan Cui
 * @Date 2024-01-16 15:09
 * @Version 1.0
 */
@Service
@EnableConfigurationProperties({WechatOpenProperties.class})
public class WechatOpenService extends WxOpenServiceImpl {
    private Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    protected LogHandler logHandler;

    @Autowired
    protected NullHandler nullHandler;

    @Autowired
    protected KfSessionHandler kfSessionHandler;

    @Autowired
    protected StoreCheckNotifyHandler storeCheckNotifyHandler;

    @Autowired
    private LocationHandler locationHandler;

    @Autowired
    private MenuHandler menuHandler;

    @Autowired
    private MsgHandler msgHandler;

    @Autowired
    private UnsubscribeHandler unsubscribeHandler;

    @Autowired
    private SubscribeHandler subscribeHandler;

    @Autowired
    private ValueOperations<String, Object> valOps;
    private WxOpenMessageRouter router;

    @Autowired
    private WechatOpenConfigStorage wechatOpenConfigStorage;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private ImServiceImpl imservice;

    @PostConstruct
    public void init() {
        super.setWxOpenConfigStorage(wechatOpenConfigStorage);
        this.refreshRouter();
//        wxOpenMessageRouter = new WxOpenMessageRouter(this);
//        wxOpenMessageRouter.rule().handler((wxMpXmlMessage, map, wxMpService, wxSessionManager) -> {
//            logger.info("\n接收到 {} 公众号请求消息,内容:{}", wxMpService.getWxMpConfigStorage().getAppId(), wxMpXmlMessage);
//            return null;
//        }).next();
    }

    private void refreshRouter() {
        final WxOpenMessageRouter newRouter = new WxOpenMessageRouter(this);

        // 记录所有事件的日志
        newRouter.rule().handler(this.logHandler).next();


        // 自定义菜单事件
        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT).event(WxConsts.MenuButtonType.CLICK).handler(
                this.getMenuHandler()).end();

        // 点击菜单连接事件
        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT).event(WxConsts.MenuButtonType.VIEW).handler(
                this.nullHandler).end();

        // 关注事件
        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT).event(WxConsts.EventType.SUBSCRIBE).handler(
                this.getSubscribeHandler()).end();

        // 取消关注事件
        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT).event(WxConsts.EventType.UNSUBSCRIBE).handler(
                this.getUnsubscribeHandler()).end();

        // 上报地理位置事件
        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT).event(WxConsts.EventType.LOCATION).handler(
                this.getLocationHandler()).end();

        // 接收地理位置消息
        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION).handler(this.getLocationHandler()).end();

        // 扫码事件
        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT).event(WxConsts.EventType.SCAN).handler(
                this.getScanHandler()).end();

        // 默认
        newRouter.rule().async(false).handler(this.getMsgHandler()).end();

        this.router = newRouter;
    }

    public WxMpXmlOutMessage route(WxMpXmlMessage message) {
        try {

            if (message.getMsgId() == null) {
                return this.router.route(message);
            } else if (!valOps.getOperations().hasKey("wx_" + message.getToUser() + "_" + message.getFromUser() + "_" + String.valueOf(message.getMsgId()))) {
                valOps.set("wx_" + message.getToUser() + "_" + message.getFromUser() + "_" + String.valueOf(message.getMsgId()), String.valueOf(message.getMsgId()), 10, TimeUnit.SECONDS);
                WxMpXmlOutMessage route = this.router.route(message);

                return route;
            } else {
                logger.info("接收到了重复的消息,不予处理,msgid:{}", message.getMsgId());
            }
        } catch (Exception e) {
            this.logger.error(e.getMessage(), e);
        }

        return null;
    }

    public WxOpenMessageRouter getWxOpenMessageRouter() {
        return router;
    }

    protected AbstractHandler getScanHandler() {
        return null;
    }

    /**
     * 重写token获取方法
     */
    public String getAccessToken(String key, boolean forceRefresh) throws WxErrorException {
        Lock lock = this.wechatOpenConfigStorage.getAccessTokenLock();

        try {
            lock.lock();
            /**
             * 从redis中获取key对应的过期时间;
             * 如果该值有过期时间,就返回相应的过期时间;
             * 如果该值没有设置过期时间,就返回-1;
             * 如果没有该值,就返回-2;
             */
            String authorAppId = this.getWechatOpenConfigStorage().getAuthorAppId();
            String authorizationCode = (String) valOps.get("wxOpen:" + authorAppId);
            String refreshToken = this.getWechatOpenConfigStorage().getAuthorizerRefreshToken(null);
            String componentAccessToken = (String) redisTemplate.opsForValue().get("wx_open_component_token_" + key);

            logger.info("是否开启强制刷新微信WxOpen AuthorizerAccessToken 功能 forceRefresh:{} ,authorAppId:{} ,authorizationCode is {} ,componentAccessToken is {} ,refreshToken:{}", forceRefresh, authorAppId, authorizationCode, componentAccessToken, refreshToken);
            Long expire = redisTemplate.opsForValue().getOperations().getExpire("wx_open_token_" + this.getWechatOpenConfigStorage().getAuthorAppId());
            if (expire == -1) {
                logger.info("WxOpen AuthorizerAccessToken 没有设置过期时间 {}", "wx_open_token_" + this.getWechatOpenConfigStorage().getAuthorAppId());
            } else if (expire == -2 || forceRefresh) {

                logger.info("WxOpen AuthorizerAccessToken redis中无该值存在 {},forceRefresh is {}", "wx_open_token_" + this.getWechatOpenConfigStorage().getAuthorAppId(), forceRefresh);
                String url = getWechatOpenConfigStorage().getThirdAccessTokenUrl();
                logger.info("WxOpen AuthorizerAccessToken获取第三方访问令牌网址 is {}", url);
                if (StringUtils.isBlank(url)) {
                    url = WxOpenComponentService.API_AUTHORIZER_TOKEN_URL + "?component_access_token=" + componentAccessToken;
                    logger.info("WxOpen AuthorizerAccessToken获取第三方访问令牌网址 为 null ,开始拼接微信官方获取token接口 is {}", url);
                } else {
                    logger.info("WxOpen AuthorizerAccessToken调用token管理中心url:{}", url);
                }

                int retryTimes = 0;
                int maxRetryTimes = 10;
                do {
                    try {
                        HttpPost httpPost = new HttpPost(url);
                        if (this.getRequestHttpProxy() != null) {
                            RequestConfig config = RequestConfig.custom().setConnectTimeout(180 * 1000).setProxy(
                                    this.getRequestHttpProxy()).build();
                            httpPost.setConfig(config);
                        }
                        JSONObject jsonObject = new JSONObject();
                        //第三方appid
                        jsonObject.put("component_appid", this.getWechatOpenConfigStorage().getComponentAppId());
                        //被授权的appid
                        jsonObject.put("authorizer_appid", authorAppId);
                        //刷新Token,需要保存,否则需要重新授权
                        jsonObject.put("authorizer_refresh_token", refreshToken);
                        httpPost.setEntity(new StringEntity(JSONObject.toJSONString(jsonObject), "application/json", "utf-8"));
                        try (CloseableHttpResponse response = getRequestHttpClient().execute(httpPost)) {
                            String resultContent = new BasicResponseHandler().handleResponse(response);
                            WxError error = WxError.fromJson(resultContent);
                            if (error.getErrorCode() != 0) {
                                throw new WxErrorException(error);
                            }
                            WxOpenAuthorizerAccessToken accessToken = WxOpenAuthorizerAccessToken.fromJson(resultContent);
                            logger.info("WxOpen AuthorizerAccessToken重新获取到微信官方token信息 is {}", accessToken);
                            this.getWechatOpenConfigStorage().updateAccessToken(accessToken.getAuthorizerAccessToken(),
                                    accessToken.getExpiresIn(), this.getWechatOpenConfigStorage().getAuthorAppId(), redisTemplate, valOps, null);
                            // 直接返回token;
                            return accessToken.getAuthorizerAccessToken();
                        } finally {
                            httpPost.releaseConnection();
                        }
                    } catch (Exception e) {
                        if (retryTimes + 1 > maxRetryTimes) {
                            logger.info("WxOpen AuthorizerAccessToken token获取达到最大次数【{}】", maxRetryTimes);
                            // 最后一次重试失败后,直接抛出异常,不再等待
                            WxError error = WxError.builder().errorCode(42002).errorMsg(
                                    "token获取达到最大次数【" + maxRetryTimes + "】,调用地址:" + url).build();
                            e.printStackTrace();
                            throw new WxErrorException(error, e);
                        }
                        // -1 系统繁忙, 1000ms后重试
                        try {
                            logger.info("WxOpen AuthorizerAccessToken token获取失败,1000 ms 后重试(第{}次)", retryTimes + 1);
                            Thread.sleep(1000);
                        } catch (InterruptedException e1) {
                            throw new RuntimeException(e1);
                        }
                    }
                } while (retryTimes++ < maxRetryTimes);

            } else {
                logger.info("WxOpen AuthorizerAccessToken redis中剩余微信官方token is {},过期时间为{}", "wx_open_token_" + this.getWechatOpenConfigStorage().getAuthorAppId(), expire);

            }

        } finally {
            lock.unlock();
        }
        return String.valueOf(redisTemplate.opsForValue().get("wx_open_token_" + this.getWechatOpenConfigStorage().getAuthorAppId()));
    }

    public WechatOpenConfigStorage getWechatOpenConfigStorage() {
        return wechatOpenConfigStorage;
    }

    public String getComponentAccessToken(String key, String componentVerifyTicket) throws WxErrorException {
        Lock lock = this.wechatOpenConfigStorage.getComponentTokenLock();

        try {
            lock.lock();
            Long expire = redisTemplate.opsForValue().getOperations().getExpire("wx_open_component_token_" + key);
            logger.info("是否开启强制刷新微信开放平台ComponentAccessToken功能 key:{}  expire:{}", key, expire);
            if (expire == -1) {
                logger.info("微信开放平台ComponentAccessToken没有设置过期时间 {}", "wx_open_component_token_" + key);
            } else if (expire == -2) {
                JSONObject params = new JSONObject();
                //第三方平台的appid、appsecret
                params.put("component_appid", this.wechatOpenConfigStorage.getComponentAppId());
                params.put("component_appsecret", this.wechatOpenConfigStorage.getComponentAppSecret());
                if (StringUtils.isBlank(componentVerifyTicket)) {
                    throw new RuntimeException("微信开放平台ComponentAccessToken,第三方平台获取【验证票据】失败");
                }
                params.put("component_verify_ticket", componentVerifyTicket);
                int retryTimes = 0;
                int maxRetryTimes = 10;
                do {
                    try {
                        JSONObject data = JSONObject.parseObject(HttpClientUtil.httpPost(WxOpenComponentService.API_COMPONENT_TOKEN_URL, JSON.toJSONString(params)));
                        if (data.containsKey("component_access_token")) {
                            String componentAccessToken = data.getString("component_access_token");
                            Integer componentExpiresIn = data.getInteger("expires_in");
                            //将component_access_token存入redis中,并设置2个小时的过期时间
                            //redisTemplate.opsForValue().set(WechatOpenConst.COMPONENT_ACCESS_TOKEN+key, componentAccessToken, 60 * 60 * 2);
                            //valOps.getOperations().opsForHash().put(WechatOpenConst.COMPONENT_ACCESS_TOKEN + key, WechatOpenConst.COMPONENT_ACCESS_TOKEN_KEY, componentAccessToken);
                            this.wechatOpenConfigStorage.updateComponentToken(componentAccessToken,
                                    componentExpiresIn, null, redisTemplate, valOps, key);
                            return componentAccessToken;
                        }
                    } catch (Exception e) {
                        if (retryTimes + 1 > maxRetryTimes) {
                            logger.info("微信开放平台ComponentAccessToken获取达到最大次数【{}】", maxRetryTimes);
                            // 最后一次重试失败后,直接抛出异常,不再等待
                            WxError error = WxError.builder().errorCode(42002).errorMsg(
                                    "微信开放平台ComponentAccessToken获取达到最大次数【" + maxRetryTimes + "】,调用地址:" + WxOpenComponentService.API_COMPONENT_TOKEN_URL).build();
                            throw new WxErrorException(error, e);
                        }
                        // -1 系统繁忙, 1000ms后重试
                        try {
                            logger.info("微信开放平台ComponentAccessToken获取失败,1000 ms 后重试(第{}次)", retryTimes + 1);
                            Thread.sleep(1000);
                        } catch (InterruptedException e1) {
                            throw new RuntimeException(e1);
                        }
                    }
                } while (retryTimes++ < maxRetryTimes);

            } else {
                logger.info("微信开放平台redis中剩余微信官方ComponentAccessToken is{},过期时间 为{}", "wx_open_component_token_" + key, expire);
            }
        } finally {
            lock.unlock();
        }
        return String.valueOf(redisTemplate.opsForValue().get("wx_open_component_token_" + key));
    }

    public LogHandler getLogHandler() {
        return logHandler;
    }

    public void setLogHandler(LogHandler logHandler) {
        this.logHandler = logHandler;
    }

    public NullHandler getNullHandler() {
        return nullHandler;
    }

    public void setNullHandler(NullHandler nullHandler) {
        this.nullHandler = nullHandler;
    }

    public LocationHandler getLocationHandler() {
        return locationHandler;
    }

    public void setLocationHandler(LocationHandler locationHandler) {
        this.locationHandler = locationHandler;
    }

    public MenuHandler getMenuHandler() {
        return menuHandler;
    }

    public void setMenuHandler(MenuHandler menuHandler) {
        this.menuHandler = menuHandler;
    }

    public MsgHandler getMsgHandler() {
        return msgHandler;
    }

    public void setMsgHandler(MsgHandler msgHandler) {
        this.msgHandler = msgHandler;
    }

    public UnsubscribeHandler getUnsubscribeHandler() {
        return unsubscribeHandler;
    }

    public void setUnsubscribeHandler(UnsubscribeHandler unsubscribeHandler) {
        this.unsubscribeHandler = unsubscribeHandler;
    }

    public SubscribeHandler getSubscribeHandler() {
        return subscribeHandler;
    }

    public void setSubscribeHandler(SubscribeHandler subscribeHandler) {
        this.subscribeHandler = subscribeHandler;
    }

    public void updateAuthAccount(String key, String authorizationCode) {
        try {
            String authorAppId = this.getWechatOpenConfigStorage().getAuthorAppId();
            if (StringUtils.isEmpty(authorizationCode)) {
                authorizationCode = (String) valOps.get("wxOpen:" + authorAppId);
            }
            String refreshToken = this.getWechatOpenConfigStorage().getAuthorizerRefreshToken(null);
            JSONObject jsonObject1 = new JSONObject();
            jsonObject1.put("snsId", key);
            jsonObject1.put("authorizationCode", authorizationCode);
            jsonObject1.put("refreshToken", refreshToken);
            Imservice.getMessageApi().sendAuthMessage(JSONObject.toJSONString(jsonObject1));
        } catch (Exception e) {
            logger.error("getMessageApi().sendAuthMessage error:{}", e);
        }
    }
}

wechatopenstorage代码

package com.test.wechat.config;

import cn.binarywang.wx.miniapp.config.WxMaConfig;
import com.test.wechat.consts.WechatOpenConst;
import com.test.wechat.util.ServletUtil;
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
import me.chanjar.weixin.mp.api.WxMpConfigStorage;
import me.chanjar.weixin.open.api.WxOpenConfigStorage;
import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken;
import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

/**
 * 〈一句话功能简述〉<br>
 * 〈〉
 *
 * @author jinxin
 * @create 2019-04-17
 * @since 1.0.0
 */

@Component
public class WechatOpenConfigStorage implements WxOpenConfigStorage {
    private final static String ACCESS_TOKEN = "access_token";
    private final static String ACCESS_TOKEN_EXPIRES_TIME = "access_token_expires_time";
    private final static String AUTHORIZER_REFRESH_TOKEN = "authorizer_refresh_token";

    private final static String COMPONENT_TOKEN = "component_access_token";
    private final static String COMPONENT_TOKEN_EXPIRES_TIME = "component_access_token_expires_time";

    @Autowired
    private SnsProperties snsProperties;
    @Autowired
    private HttpProxyConfig httpProxyConfig;
    @Autowired
    private ValueOperations<String, Object> valOps;
    @Autowired
    private Lock accessTokenLock;
    @Autowired
    private Lock componentTokenLock;

    @Autowired
    RedisTemplate redisTemplate;

    private SnsProperties.SnsConfiguration getSns() {
        return snsProperties.getConfig().get(ServletUtil.getKey());
    }

    private String getKeyField() {
        return "wxOpen:" + ServletUtil.getKey();
    }

    public Lock getComponentTokenLock() {
        return componentTokenLock;
    }

    public void setComponentTokenLock(Lock componentTokenLock) {
        this.componentTokenLock = componentTokenLock;
    }

    //作为第三方平台appid
    @Override
    public String getComponentAppId() {
        return getSns().getWechatAppId();
    }

    @Override
    public void setComponentAppId(String s) {

    }

    //第三方开放平台secret
    @Override
    public String getComponentAppSecret() {
        return getSns().getWechatAppSecret();
    }

    @Override
    public void setComponentAppSecret(String s) {

    }

    //第三方平台Token
    @Override
    public String getComponentToken() {
        return getSns().getWechatToken();
    }

    @Override
    public void setComponentToken(String s) {

    }

    //第三方消息加解密Key
    @Override
    public String getComponentAesKey() {
        return getSns().getWechatAesKey();
    }

    @Override
    public void setComponentAesKey(String s) {

    }

    @Override
    public String getComponentVerifyTicket() {
        return null;
    }

    @Override
    public void setComponentVerifyTicket(String s) {

    }

    @Override
    public String getComponentAccessToken() {
        return valOps.getOperations().opsForHash().get(WechatOpenConst.COMPONENT_ACCESS_TOKEN+ServletUtil.getKey(),WechatOpenConst.COMPONENT_ACCESS_TOKEN_KEY)+"";
    }

    @Override
    public boolean isComponentAccessTokenExpired() {
        return false;
    }

    @Override
    public void expireComponentAccessToken() {

    }

    @Override
    public void updateComponentAccessTokent(WxOpenComponentAccessToken wxOpenComponentAccessToken) {

    }

    @Override
    public String getHttpProxyHost() {
        return httpProxyConfig.getHttpProxyHost();
    }

    @Override
    public int getHttpProxyPort() {
        return httpProxyConfig.getHttpProxyPort();
    }

    @Override
    public String getHttpProxyUsername() {
        return httpProxyConfig.getHttpProxyUsername();
    }

    @Override
    public String getHttpProxyPassword() {
        return httpProxyConfig.getHttpProxyPassword();
    }

    @Override
    public ApacheHttpClientBuilder getApacheHttpClientBuilder() {
        return null;
    }

    @Override
    public WxMpConfigStorage getWxMpConfigStorage(String s) {
        return null;
    }

    @Override
    public WxMaConfig getWxMaConfig(String s) {
        return null;
    }

    @Override
    public void updateComponentAccessTokent(String s, int i) {

    }

    @Override
    public boolean autoRefreshToken() {
        return false;
    }

    @Override
    public String getAuthorizerRefreshToken(String s) {
        return (String) valOps.getOperations().opsForHash().get(getKeyField(), AUTHORIZER_REFRESH_TOKEN);
    }

    @Override
    public void setAuthorizerRefreshToken(String s, String s1) {
        valOps.getOperations().opsForHash().put(getKeyField(), AUTHORIZER_REFRESH_TOKEN, s1);
    }

    @Override
    public String getAuthorizerAccessToken(String s) {
        return null;
    }

    @Override
    public boolean isAuthorizerAccessTokenExpired(String s) {
        return false;
    }

    @Override
    public void expireAuthorizerAccessToken(String s) {

    }

    @Override
    public void updateAuthorizerAccessToken(String s, WxOpenAuthorizerAccessToken wxOpenAuthorizerAccessToken) {

    }

    @Override
    public void updateAuthorizerAccessToken(String s, String s1, int expireTimes) {
        valOps.getOperations().opsForHash().put(getKeyField(), ACCESS_TOKEN, s1);
        valOps.getOperations().opsForHash().put(getKeyField(), ACCESS_TOKEN_EXPIRES_TIME, System.currentTimeMillis() + (expireTimes - 200) * 1000L);
    }

    @Override
    public String getJsapiTicket(String s) {
        return null;
    }

    @Override
    public boolean isJsapiTicketExpired(String s) {
        return false;
    }

    @Override
    public void expireJsapiTicket(String s) {

    }

    @Override
    public void updateJsapiTicket(String s, String s1, int i) {

    }

    @Override
    public String getCardApiTicket(String s) {
        return null;
    }

    @Override
    public boolean isCardApiTicketExpired(String s) {
        return false;
    }

    @Override
    public void expireCardApiTicket(String s) {

    }

    @Override
    public void updateCardApiTicket(String s, String s1, int i) {

    }

    public Lock getAccessTokenLock() {
        return this.accessTokenLock;
    }

    //第三方授权appId
    public String getAuthorAppId() {
        return getSns().getDataformat();
    }

    public String getThirdAccessTokenUrl() {
        return getSns().getThirdAccessTokenUrl();
    }

    public void updateAccessToken(String accessToken, int expiresInSeconds, String appId, RedisTemplate<String, Object> redisTemplate, ValueOperations<String, Object> valOps, String snsUuid) {
        //为提供获取微信官方token接口单独存入redis
        redisTemplate.opsForValue().set("wx_open_token_" + appId, accessToken, (expiresInSeconds - 3600), TimeUnit.SECONDS);
        if ("wx:null".equals(getKeyField())) {
            valOps.getOperations().opsForHash().put("wxOpen:" + snsUuid, ACCESS_TOKEN, accessToken);
            valOps.getOperations().opsForHash().put("wxOpen:" + snsUuid, ACCESS_TOKEN_EXPIRES_TIME, System.currentTimeMillis() + (expiresInSeconds - 3600) * 1000L);
        } else {
            valOps.getOperations().opsForHash().put(getKeyField(), ACCESS_TOKEN, accessToken);
            valOps.getOperations().opsForHash().put(getKeyField(), ACCESS_TOKEN_EXPIRES_TIME, System.currentTimeMillis() + (expiresInSeconds - 3600) * 1000L);
        }
    }

    public void updateComponentToken(String accessToken, int expiresInSeconds, String appId, RedisTemplate<String, Object> redisTemplate, ValueOperations<String, Object> valOps, String snsUuid) {
        //为提供获取微信官方token接口单独存入redis
        redisTemplate.opsForValue().set("wx_open_component_token_" + snsUuid, accessToken, (expiresInSeconds - 3600), TimeUnit.SECONDS);
        if (ServletUtil.getKey()==null) {
            valOps.getOperations().opsForHash().put(WechatOpenConst.COMPONENT_ACCESS_TOKEN + snsUuid, COMPONENT_TOKEN, accessToken);
            valOps.getOperations().opsForHash().put(WechatOpenConst.COMPONENT_ACCESS_TOKEN + snsUuid, COMPONENT_TOKEN_EXPIRES_TIME, System.currentTimeMillis() + (expiresInSeconds - 3600) * 1000L);
        } else {
            valOps.getOperations().opsForHash().put(WechatOpenConst.COMPONENT_ACCESS_TOKEN+ServletUtil.getKey(), COMPONENT_TOKEN, accessToken);
            valOps.getOperations().opsForHash().put(WechatOpenConst.COMPONENT_ACCESS_TOKEN+ServletUtil.getKey(), COMPONENT_TOKEN_EXPIRES_TIME, System.currentTimeMillis() + (expiresInSeconds - 3600) * 1000L);
        }
    }

}

介绍一个msghandler,这部分参考weixin-java-mp模块。

package com.test.wechat.handler;

import com.test.sdk.exception.ImccErrorException;
import com.test.sdk.service.impl.ImccServiceImpl;
import me.chanjar.weixin.common.api.WxConsts;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * @author Binary Wang
 */
@Component
public class MenuHandler extends AbstractHandler {
    @Autowired
    private ImccServiceImpl imccservice;

    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService,
                                    WxSessionManager sessionManager) {
        //    WechatService weixinService = (WechatService) wxMpService;
        String key = wxMessage.getEventKey();
        String event = wxMessage.getEvent();
        switch (event.toLowerCase()) {
            case WxConsts.MenuButtonType.CLICK:
                //case WxConsts.BUTTON_VIEW :
                try {
                    imccservice.getMessageApi().sendClickMsg(wxMessage.getToUser(), wxMessage.getFromUser(),
                            wxMessage.getCreateTime(), key);
                } catch (ImccErrorException e) {
                    return WxMpXmlOutMessage.TEXT().content("服务器未响应,请稍后再试").fromUser(wxMessage.getToUser()).toUser(
                            wxMessage.getFromUser()).build();
                }
                return null;
            default:
                return WxMpXmlOutMessage.TEXT().content("此菜单未定义").fromUser(wxMessage.getToUser()).toUser(
                        wxMessage.getFromUser()).build();
        }

        //    WxMenuKey menuKey = null;
        //    try {
        //      menuKey = JSON.parseObject(key, WxMenuKey.class);
        //    } catch (Exception e) {
        //      return WxMpXmlOutMessage.TEXT().content(key)
        //          .fromUser(wxMessage.getToUser())
        //          .toUser(wxMessage.getFromUser()).build();
        //    }
        //
        //    WeChatAbstractBuilder builder = null;
        //    switch (menuKey.getType()) {
        //    case WxConsts.XML_MSG_TEXT:
        //      builder = new WeChatTextBuilder();
        //      break;
        //    case WxConsts.XML_MSG_IMAGE:
        //      builder = new WeChatImageBuilder();
        //      break;
        //    case WxConsts.XML_MSG_VOICE:
        //      break;
        //    case WxConsts.XML_MSG_VIDEO:
        //      break;
        //    case WxConsts.XML_MSG_NEWS:
        //      break;
        //    default:
        //      break;
        //    }
        //
            if (builder != null) {
              try {
                return builder.build(menuKey.getContent(), wxMessage, weixinService);
              } catch (Exception e) {
                this.logger.error(e.getMessage(), e);
              }
            }
        //
        //    return null;

    }

}

 注,其中redis实现使用自己项目中的即可。

ps:下节继续看消息如何发送。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/358297.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SV-8003V 网络寻呼话筒

SV-8003V是深圳锐科达电子有限公司的一款桌面式对讲主机SV-8003V同样作为广播对讲系统的核心组成部分&#xff0c;集成有全区广播、分区广播、单点呼叫、点对点对讲、以及监听等功能。SV-8003V使用铝合金拉丝面板&#xff0c;并配有高性能的鹅颈麦克风以及高保真的全频喇叭&…

Linux(CentOS7)与用户电脑传输文件(sz与rz)云与云(scp)

rz和sz是Linux/Unix同Windows进行Zmodem文件传输的命令工具 rz和sz中的z为Zmodem文件传输协议的首字母 s为send发送 r为receive接收&#xff0c;都是相对与Linux来看的接收和发送 Linux发送文件到电脑&#xff1a; sz命令 把文件发送到Windows sz 文件直接按回车就可以选择发送…

亚信安慧AntDB:AntDB-M元数据锁(五)

IS_DESTROYED: 标识锁对象将被释放。 HAS_OBTRUSIVE&#xff1a;标识锁对象下有obtrusive锁&#xff0c;新的锁申请必须进入慢速申请路径&#xff0c;释放锁时&#xff0c;也要先加锁以保护已授予锁链表。 HAS_SLOW_PATH: 标识锁对象下是否有unobtrusive锁。 5.3.2 干扰型(o…

船舶船体结构型面/曲面精度一致性三维检测海船提取结构几何参数

船舶船体结构型面三维扫描测量是一种高科技的测量方法&#xff0c;它利用三维激光扫描仪对船体表面进行高精度测量&#xff0c;以获取船体结构型面的三维数据。这种测量方法在船舶设计和制造中具有重要意义&#xff0c;可以为船舶工程师提供精确的数据支持&#xff0c;帮助他们…

《HTML 简易速速上手小册》第8章:HTML 表单高级技术(2024 最新版)

文章目录 8.1 数据收集与处理8.1.1 基础知识8.1.2 案例 1&#xff1a;创建一个注册表单8.1.3 案例 2&#xff1a;创建一个调查问卷表单8.1.4 案例 3&#xff1a;创建一个动态添加输入字段的表单 8.2 定制化表单元素8.2.1 基础知识8.2.2 案例 1&#xff1a;创建一个带有定制选择…

【Java】Lombok的使用

一、Lombok是什么&#xff1f; Lombok是一个Java库&#xff0c;能自动插入编辑器并构建工具&#xff0c;简化Java开发。通过添加注解的方式&#xff0c;不需要为类编写getter或eques方法&#xff0c;同时可以自动化日志变量&#x1f680; 在我们封装一个类时&#xff0c;最常用…

JMeter 性能测试基本过程及示例

jmeter 为性能测试提供了一下特色&#xff1a; jmeter 可以对测试静态资源&#xff08;例如 js、html 等&#xff09;以及动态资源&#xff08;例如 php、jsp、ajax 等等&#xff09;进行性能测试 jmeter 可以挖掘出系统最大能处理的并发用户数 jmeter 提供了一系列各种形式的…

【UE 材质】闪电材质

效果 步骤 1. 新建一个材质这里命名为“M_Lighting” 打开“M_Lighting”&#xff0c;设置混合模式为半透明&#xff0c;着色模型为无光照 在材质图表中添加如下节点 其中&#xff0c;纹理采样节点的纹理是一个线条 此时预览窗口中效果如文章开头所示。

基于链表实现贪吃蛇游戏

本文中&#xff0c;我们将使用链表和一些Win32 API的知识来实现贪吃蛇小游戏 一、功能 &#xff08;1&#xff09;游戏载入界面 &#xff08;2&#xff09;地图的绘制 &#xff08;3&#xff09;蛇身的移动和变长 &#xff08;4&#xff09;食物的生成 &#xff08;5&…

数学建模学习笔记||灰色关联分析

灰色系统 信息绝对透明的是白色系统&#xff0c;信息绝对秘密的是黑色系统&#xff0c;灰色系统介于两者之间 关联分析 即系统的分析因素 包含多种因素的系统中&#xff0c;哪些因素是主要的&#xff0c;哪些因素是次要的&#xff0c;哪些因素影响大&#xff0c;哪些因素影响小…

vue3+typescript+Vite基础简单项目

gitee地址 数据大屏 菜单管理

【Java反序列化】Shiro-550漏洞分析笔记

目录 前言 一、漏洞原理 二、Shiro环境搭建 三、Shiro-550漏洞分析 解密分析 加密分析 四、URLDNS 链 前言 shiro-550反序列化漏洞大约在2016年就被披露了&#xff0c;在上学时期也分析过&#xff0c;最近在学CC链时有用到这个漏洞&#xff0c;重新分析下并做个笔记&…

希尔伯特变换的在信号解调时的示例

1.希尔伯特变换的应用场景 希尔伯特变换&#xff0c;在数学上的含义是清晰的。它是一个数字移相器&#xff0c;可以把通过它的任何一个信号相移-90度。这个数学工具在信号解调时&#xff0c;会有非常有用的特性出现。可以看示例&#xff1a; 解释一下&#xff1a; 1.最上面的…

Nuget包缓存存放位置迁移

本文介绍了如何通过环境变量修改Nuget包缓存的存放位置。 一、背景 默认情况下&#xff0c;NuGet会将项目中使用的包缓存到C盘&#xff0c;随着项目开发积累nuget包越来越多&#xff0c;这会逐渐挤占大量C盘空间&#xff0c;所以我们可以将nuget包缓存位置指定到其他盘中存放…

秋招面试—浏览器原理篇

浏览器原理篇 1.什么是XSS、CSRF,怎么预防&#xff1f; &#xff08;1&#xff09;XSS(跨站脚本攻击)&#xff1a;攻击者将恶意代码植入到浏览器页面中&#xff0c;盗取存储在客户端的Cookie&#xff1b; ​ XSS分为&#xff1a;①存储型&#xff1a;论坛发帖、商品评论、用户…

(2024,CompAgent,LLM,提示分解,基于布局的对象组合)分而治之:语言模型可以规划和自我纠正组合文本到图像的生成

Divide and Conquer: Language Models can Plan and Self-Correct for Compositional Text-to-Image Generation 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 3. 方法 3.1…

Golang 流媒体服务器lalserver使用指南

目录 安装 使用 1.推流 2.播放 官方地址 安装 1.下载源码 wget https://github.com/q191201771/lal/releases/download/v0.36.7/lal_v0.36.7_linux.zipunzip lal_v0.36.7_linux.zip cd lal_v0.36.7_linux 2.启动 ./bin/lalserver -c ./conf/lalserver.conf.json 使用 …

C语言第十三弹---VS使用调试技巧

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 VS调试技巧 1、什么是bug 2、什么是调试&#xff08;debug&#xff09;&#xff1f; 3、Debug和Release​编辑​ 4、VS调试快捷键 4.1、环境准备 4.2、调试…

java.util.LinkedHashSet cannot be cast to java.util.List 的解决方案

出现 “java.util.LinkedHashSet cannot be cast to java.util.List” 的错误&#xff0c;通常是因为你试图将一个 LinkedHashSet 对象直接强制转换为 List 类型。在 Java 中&#xff0c;LinkedHashSet 和 List 是两种不同的集合类型&#xff0c;不能直接进行转换。LinkedHashS…

小白水平理解面试经典题目LeetCode 455 Assign Cookies【Java实现】

455 分配cookies 小白渣翻译&#xff1a; 假设你是一位很棒的父母&#xff0c;想给你的孩子一些饼干。但是&#xff0c;你最多应该给每个孩子一块饼干。 每个孩子 i 都有一个贪婪因子 g[i] &#xff0c;这是孩子满意的 cookie 的最小大小&#xff1b;每个 cookie j 都有一个…