spring boot 集成wxjava 实现扫码登入

引入pom

   <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-mp</artifactId>
            <version>4.4.0</version>
        </dependency>

配置文件

package com.xz.zriyochat.common.config;

import cn.hutool.json.JSONUtil;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.List;

/**
 * wechat mp properties
 *
 * 
 */
@Data
@ConfigurationProperties(prefix = "wx.mp")
public class WxMpProperties {
    /**
     * 是否使用redis存储access token
     */
    private boolean useRedis;

    /**
     * redis 配置
     */
    private RedisConfig redisConfig;

    @Data
    public static class RedisConfig {
        /**
         * redis服务器 主机地址
         */
        private String host;

        /**
         * redis服务器 端口号
         */
        private Integer port;

        /**
         * redis服务器 密码
         */
        private String password;

        /**
         * redis 服务连接超时时间
         */
        private Integer timeout;
    }

    /**
     * 多个公众号配置信息
     */
    private List<MpConfig> 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 JSONUtil.toJsonStr(this);
    }
}

package com.xz.zriyochat.common.config;

import com.xz.zriyochat.common.user.service.handler.LogHandler;
import com.xz.zriyochat.common.user.service.handler.MsgHandler;
import com.xz.zriyochat.common.user.service.handler.ScanHandler;
import com.xz.zriyochat.common.user.service.handler.SubscribeHandler;
import lombok.AllArgsConstructor;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;
import java.util.stream.Collectors;

import static me.chanjar.weixin.common.api.WxConsts.EventType;
import static me.chanjar.weixin.common.api.WxConsts.EventType.SUBSCRIBE;
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType.EVENT;

/**
 * 
 *
 *
 */
@AllArgsConstructor
@Configuration
@EnableConfigurationProperties(WxMpProperties.class)
public class WxMpConfiguration {
    private final LogHandler logHandler;
    private final MsgHandler msgHandler;
    private final SubscribeHandler subscribeHandler;
    private final ScanHandler scanHandler;
    private final WxMpProperties properties;

    @Bean
    public WxMpService wxMpService() {
        // 代码里 getConfigs()处报错的同学,请注意仔细阅读项目说明,你的IDE需要引入lombok插件!!!!
        final List<WxMpProperties.MpConfig> configs = this.properties.getConfigs();
        if (configs == null) {
            throw new RuntimeException("大哥,拜托先看下项目首页的说明(readme文件),添加下相关配置,注意别配错了!");
        }

        WxMpService service = new WxMpServiceImpl();
        service.setMultiConfigStorages(configs
                                       .stream().map(a -> {
                                           WxMpDefaultConfigImpl configStorage;
                                           configStorage = new WxMpDefaultConfigImpl();

                                           configStorage.setAppId(a.getAppId());
                                           configStorage.setSecret(a.getSecret());
                                           configStorage.setToken(a.getToken());
                                           configStorage.setAesKey(a.getAesKey());
                                           return configStorage;
                                       }).collect(Collectors.toMap(WxMpDefaultConfigImpl::getAppId, a -> a, (o, n) -> o)));
        return service;
    }

    @Bean
    public WxMpMessageRouter messageRouter(WxMpService wxMpService) {
        final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);

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

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

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

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

        return newRouter;
    }

    }

这里用的是Netty websocket

websocket建立连接后 服务器接收到消息后

/**
     * 接受到消息后
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        String text = msg.text();
        WSBaseReq bean = JSONUtil.toBean(text, WSBaseReq.class);
        switch (WSReqTypeEnum.of(bean.getType())){
            case LOGIN:
                log.info("请求登入二维码");
                webSocketService.handleLoginRed(ctx.channel());
            case AUTHORIZE:
                break;
            case HEARTBEAT:
                break;
        }
    }

生成随机码和channel关联 并推送给前端

 @Override
    public void handleLoginRed(Channel channel) {
        //生成随机码
        Integer code = GenerateLoginCode(channel);
        //申请微信带参二维码
        try {
            WxMpQrCodeTicket url = wxMpService.getQrcodeService().qrCodeCreateTmpTicket(code, (int) DURATION.getSeconds());
            //推送url给前端
            WSBaseResp<?> wsBaseResp = WebSocketAdapter.buildResp(url);
            sandMsg(channel, wsBaseResp);
        } catch (WxErrorException e) {
            throw new RuntimeException(e);
        }
    }

用户扫码后根据扫码后对应的状态 新用户/老用户

新用户/老用户 都是调用这个方法

//如果用户存在/老用户
 if (registered && authorized) {
            //走到登入成功逻辑通过code找到给channel推送token
            webSocketService.UserLoginChannel(code, user.getId());
        }

	//新关注用户还未授权
        if (!registered) {
            User insert = UserAdapter.buildUserSava(openId);
            userService.register(insert);
        }

WX_CHAT_AUTH_CODE.put(openId,code); 这里把openid和code关联起来 可以用openid获取code和channel关联

 public WxMpXmlOutMessage scan(WxMpXmlMessage wxMessage) {
        //获取openid
        String openId = wxMessage.getFromUser();
        Integer code = getEventKey(wxMessage);
        if (Objects.isNull(code)) {
            return null;
        }
        //openid和code关联
        WX_CHAT_AUTH_CODE.put(openId,code);
        //判断用户是否存在
        User user = userDao.getOpenid(openId);
        boolean registered = Objects.nonNull(user);
        boolean authorized = Objects.nonNull(user) && Strings.isNotBlank(user.getName());
        if (registered && authorized) {
            //走到登入成功逻辑通过code找到给channel推送token
            webSocketService.UserLoginChannel(code, user.getId());
        }
        //没有进行授权
        if (!registered) {
            User insert = UserAdapter.buildUserSava(openId);
            userService.register(insert);
        }
        String cleanCallback = callback.replace("\"", "");
        log.info("\n扫码后的消息,内容:{}", JSONUtil.toJsonStr(wxMessage));
        //字符串拼接
        String empower = String.format(URL, wxMpService.getWxMpConfigStorage().getAppId(), URLEncoder.encode(cleanCallback + "/wx/portal/public/callBack"));
        return new TextBuilder().build("请点击登入:<a href=\"" + empower + "\">登入</a>", wxMessage, wxMpService);
    }
   

用户登入了 推送消息token用户信息给前端

   @Override
 public void UserLoginChannel(Integer code, Long uid) {
     Channel channel = WAIT_LOGIN_MAP.getIfPresent(code);
     if (Objects.isNull(channel)) {
         return;
     }
     User user = userDao.getById(uid);
     //移除code
     WAIT_LOGIN_MAP.invalidate(code);
     //调用登入模块获取token
     String token = loginService.login(uid);
     //用户登入发送消息
     sandMsg(channel, WebSocketAdapter.buildResp(user, token));
 }

关系图

游客->channel->随机事件码code->openId
openId<-随机事件码<-channel<-游客
可以互相关联在这里插入图片描述

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值