【SpringBoot学习】38、SpringBoot 集成 wxJava 微信小程序:授权登录

SpringBoot 集成 wxJava 微信小程序:授权登录

1、整合 wxJava 小程序

导入相关依赖,最新版本的可以查看官方文档 wxJava

<!-- wxjava小程序 -->
        <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-miniapp</artifactId>
            <version>4.2.0</version>
        </dependency>

2、小程序配置类

直接复制粘贴到项目

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage;
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import cn.binarywang.wx.miniapp.message.WxMaMessageHandler;
import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.error.WxRuntimeException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author <a href="https://github.com/binarywang">Binary Wang</a>
 */

@Slf4j
@Configuration
@EnableConfigurationProperties(WxMaProperties.class)
public class WxMaConfiguration 
{
    private static final Map<String, WxMaMessageRouter> routers = Maps.newHashMap();
    private static Map<String, WxMaService> maServices;
    private final WxMaProperties properties;
    private final WxMaMessageHandler subscribeMsgHandler = (wxMessage, context, service, sessionManager) -> {
        service.getMsgService().sendSubscribeMsg(WxMaSubscribeMessage.builder()
                .templateId("此处更换为自己的模板id")
                .data(Lists.newArrayList(
                        new WxMaSubscribeMessage.MsgData("keyword1""339208499")))
                .toUser(wxMessage.getFromUser())
                .build());
        return null;
    };
    private final WxMaMessageHandler logHandler = (wxMessage, context, service, sessionManager) -> {
        log.info("收到消息:" + wxMessage.toString());
        service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("收到信息为:" + wxMessage.toJson())
                .toUser(wxMessage.getFromUser()).build());
        return null;
    };
    private final WxMaMessageHandler textHandler = (wxMessage, context, service, sessionManager) -> {
        service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("回复文本消息")
                .toUser(wxMessage.getFromUser()).build());
        return null;
    };
    private final WxMaMessageHandler picHandler = (wxMessage, context, service, sessionManager) -> {
        try {
            WxMediaUploadResult uploadResult = service.getMediaService()
                    .uploadMedia("image""png",
                            ClassLoader.getSystemResourceAsStream("tmp.png"));
            service.getMsgService().sendKefuMsg(
                    WxMaKefuMessage
                            .newImageBuilder()
                            .mediaId(uploadResult.getMediaId())
                            .toUser(wxMessage.getFromUser())
                            .build());
        } catch (WxErrorException e) {
            e.printStackTrace();
        }

        return null;
    };
    private final WxMaMessageHandler qrcodeHandler = (wxMessage, context, service, sessionManager) -> {
        try {
            final File file = service.getQrcodeService().createQrcode("123"430);
            WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia("image", file);
            service.getMsgService().sendKefuMsg(
                    WxMaKefuMessage
                            .newImageBuilder()
                            .mediaId(uploadResult.getMediaId())
                            .toUser(wxMessage.getFromUser())
                            .build());
        } catch (WxErrorException e) {
            e.printStackTrace();
        }

        return null;
    };

    @Autowired
    public WxMaConfiguration(WxMaProperties properties) {
        this.properties = properties;
    }

    public static WxMaService getMaService(String appid) {
        WxMaService wxService = maServices.get(appid);
        if (wxService == null) {
            throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
        }

        return wxService;
    }

    public static WxMaMessageRouter getRouter(String appid) {
        return routers.get(appid);
    }

    @PostConstruct
    public void init() {
        List<WxMaProperties.Config> configs = this.properties.getConfigs();
        if (configs == null) {
            throw new WxRuntimeException("大哥,拜托先看下项目首页的说明(readme文件),添加下相关配置,注意别配错了!");
        }

        maServices = configs.stream()
                .map(a -> {
                    WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
//                WxMaDefaultConfigImpl config = new WxMaRedisConfigImpl(new JedisPool());
                    // 使用上面的配置时,需要同时引入jedis-lock的依赖,否则会报类无法找到的异常
                    config.setAppid(a.getAppid());
                    config.setSecret(a.getSecret());
                    config.setToken(a.getToken());
                    config.setAesKey(a.getAesKey());
                    config.setMsgDataFormat(a.getMsgDataFormat());

                    WxMaService service = new WxMaServiceImpl();
                    service.setWxMaConfig(config);
                    routers.put(a.getAppid(), this.newRouter(service));
                    return service;
                }).collect(Collectors.toMap(s -> s.getWxMaConfig().getAppid(), a -> a));
    }

    private WxMaMessageRouter newRouter(WxMaService service) {
        final WxMaMessageRouter router = new WxMaMessageRouter(service);
        router
                .rule().handler(logHandler).next()
                .rule().async(false).content("订阅消息").handler(subscribeMsgHandler).end()
                .rule().async(false).content("文本").handler(textHandler).end()
                .rule().async(false).content("图片").handler(picHandler).end()
                .rule().async(false).content("二维码").handler(qrcodeHandler).end();
        return router;
    }

}

package com.ruoyi.business.miniapp.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.List;

/**
 * @author <a href="https://github.com/binarywang">Binary Wang</a>
 */

@Data
@ConfigurationProperties(prefix = "wx.miniapp")
public class WxMaProperties {

    private List<Config> configs;

    @Data
    public static class Config {
        /**
         * 设置微信小程序的appid
         */

        private String appid;

        /**
         * 设置微信小程序的Secret
         */

        private String secret;

        /**
         * 设置微信小程序消息服务器配置的token
         */

        private String token;

        /**
         * 设置微信小程序消息服务器配置的EncodingAESKey
         */

        private String aesKey;

        /**
         * 消息格式,XML或者JSON
         */

        private String msgDataFormat;
    }

}

3、application.yml 配置

# 微信配置
wx:
  miniapp:
    configs:
      - appid: #微信小程序的appid
        secret: #微信小程序的Secret
        token: #微信小程序消息服务器配置的token
        aesKey: #微信小程序消息服务器配置的EncodingAESKey
        msgDataFormat: JSON

4、授权登录流程

控制层

    @Autowired
    private WxMiniappService wxMiniappService;

    @ApiOperation("登录")
    @PostMapping("login")
    public AjaxResult login(@RequestBody WxLoginVo entity) {
        return wxMiniappService.login(entity);
    }

service 接口

    /**
     * 授权登录
     *
     * @param entity
     * @return
     */

    AjaxResult login(WxLoginVo entity);

service 接口实现类

@Override
    public AjaxResult login(WxLoginVo entity) {
        if (StringUtils.isBlank(entity.getCode())) {
            return AjaxResult.error("code不能为空");
        }
        String appid = wxMaProperties.getConfigs().get(0).getAppid();
        final WxMaService wxService = WxMaConfiguration.getMaService(appid);
        try {
            // code换取session
            WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(entity.getCode());
            log.info("code换取session:{}", session);
            // 用户信息校验
            if (!wxService.getUserService().checkUserInfo(session.getSessionKey(), entity.getRawData(), entity.getSignature())) {
                return AjaxResult.error("用户信息校验失败");
            }
            // 解密用户信息
            WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(session.getSessionKey(), entity.getEncryptedData(), entity.getIv());
            log.info("解密用户信息:{}", userInfo);
            // 获取用户绑定手机号信息
            WxMaPhoneNumberInfo phoneNoInfo = wxService.getUserService().getPhoneNoInfo(session.getSessionKey(), entity.getEncryptedData(), entity.getIv());
            log.info("获取用户绑定手机号信息:{}", phoneNoInfo);

            // =============================== 处理业务
            // 根据openId查询是否存在这个用户
            List<SysUser> list = userService.list(new LambdaQueryWrapper<SysUser>().eq(SysUser::getOpenId, session.getOpenid()).or().eq(SysUser::getUserName, phoneNoInfo.getPhoneNumber()).or().eq(SysUser::getPhonenumber, phoneNoInfo.getPhoneNumber()));
            AjaxResult ajax = AjaxResult.success();
            if (CollectionUtils.isEmpty(list)) {
                // 添加新用户
                String defaultPassword = sysConfigService.selectConfigByKey("sys.user.initPassword");
                SysUser user = new SysUser().setOpenId(session.getOpenid()).setUserName(phoneNoInfo.getPhoneNumber()).setNickName(userInfo.getNickName()).setDeptId(0L).setPassword(defaultPassword).setPhonenumber(phoneNoInfo.getPhoneNumber()).setAvatar(userInfo.getAvatarUrl());
                handleUseSex(userInfo, user);
                if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user.getUserName()))) {
                    return AjaxResult.error("手机号已被注册");
                } else if (Validator.isNotEmpty(user.getPhonenumber()) && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) {
                    return AjaxResult.error("手机号已被使用");
                }
                user.setCreateBy(SecurityUtils.getUsername());
                user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
                // 默认给角色用户
                user.setRoleIds(new Long[]{1L});
                userService.insertUser(user);
                String token = loginService.login(user.getUserName(), defaultPassword);
                ajax.put(Constants.TOKEN, token);
                return ajax;
            } else if (list.size() == 1) {
                // 更新用户信息
                SysUser sysUser = list.get(0);
                sysUser.setNickName(userInfo.getNickName());
                sysUser.setAvatar(userInfo.getAvatarUrl());
                handleUseSex(userInfo, sysUser);
                sysUser.setOpenId(session.getOpenid());
                userService.updateById(sysUser);
                SysUser user = userService.selectUserByUserName(sysUser.getUserName());
                LoginUser loginUser = new LoginUser(user, permissionService.getMenuPermission(user));
                String token = tokenService.createToken(loginUser);
                ajax.put(Constants.TOKEN, token);
                return ajax;
            } else {
                return AjaxResult.error("用户信息异常,存在多个openId或电话号码");
            }
        } catch (WxErrorException e) {
            log.error(e.toString());
            return AjaxResult.error(e.getError().getErrorMsg());
        }
    }

JsonUtils

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

/**
 * @author <a href="https://github.com/binarywang">Binary Wang</a>
 */

public class JsonUtils {
    private static final ObjectMapper JSON = new ObjectMapper();

    static {
        JSON.setSerializationInclusion(Include.NON_NULL);
        JSON.configure(SerializationFeature.INDENT_OUTPUT, Boolean.TRUE);
    }

    public static String toJson(Object obj) {
        try {
            return JSON.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        return null;
    }
}

WxLoginVo

package com.ruoyi.business.miniapp.vo;

import lombok.Data;
import lombok.experimental.Accessors;

/**
 * 微信登录参数
 *
 * @author Tellsea
 * @date 2022/3/25
 */

@Data
@Accessors(chain = true)
public class WxLoginVo {

    /**
     * 微信返回的code
     */

    private String code;
    /**
     * 非敏感的用户信息
     */

    private String rawData;
    /**
     * 签名信息
     */

    private String signature;
    /**
     * 加密的数据
     */

    private String encryptedData;
    /**
     * 加密密钥
     */

    private String iv;
}

OK ,到此后端调用逻辑都完成了

5、uniapp 前端

<template>
  <view>
    <view style="padding: 15px;">
      <view class="global-btn">
        <u-button type="primary" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
          <u-icon size="70" name="weixin-fill" color="rgb(83,194,64)"></u-icon>
          <view>微信小程序授权登录</view>
        </u-button>
      </view>

      <u-cell-group>
        <u-cell-item icon="woman" title="订单支付" @click="toPage('/pages/miniapp/createOrder')"></u-cell-item>
        <u-cell-item icon="woman" title="订单退款" @click="toPage('/pages/miniapp/refund')"></u-cell-item>
        <u-cell-item icon="woman" title="模板消息" @click="toPage('/pages/miniapp/sedMessage')"></u-cell-item>
      </u-cell-group>
    </view>
    <u-toast ref="uToast" />
  </view>
</template>

<script>
let that;
export default {
  data() {
    return {
      baseUrlthis.$config.baseUrl,
      form: {
        // 换取openId
        code'',
        rawData'',
        signature'',
        // 解密手机号
        encryptedData'',
        iv'',
      }
    }
  },
  onLoad() {
    that = this;
    this.getCode();
  },
  methods: {
    getCode() {
      wx.login({
        success(res) {
          if (res.code) {
            that.form.code = res.code;
          } else {
            that.$msg('登录失败:' + res.errMsg);
          }
        },
        fail(err) {
          that.$msg('code获取失败');
        },
      });
    },
    getPhoneNumberfunction(e{
      that.getCode();
      uni.showLoading({
        title'登录中...'
      });
      if (e.detail.errMsg != 'getPhoneNumber:ok') {
        that.$refs.uToast.show({
          type'error',
          title'未授权手机号'
        });
        uni.hideLoading();
        return false;
      }
      that.form.encryptedData = e.detail.encryptedData;
      that.form.iv = e.detail.iv;
      // 检查登录态是否过期
      wx.checkSession({
        success() {
          // 用户信息
          wx.getUserInfo({
            successfunction(result{
              that.form.rawData = result.rawData;
              that.form.signature = result.signature;
              that.$u.post('/au/wxMiniapp/login', that.form).then(res => {
                uni.setStorageSync(that.$config.cachePrefix + 'token', res.token);
                that.$u.get('/au/wxMiniapp/getInfo').then(result => {
                  uni.setStorageSync(that.$config.cachePrefix + 'user', result.user);
                  uni.setStorageSync(that.$config.cachePrefix + 'roles', result.roles);
                  uni.setStorageSync(that.$config.cachePrefix + 'permissions', result.permissions);
                  that.$refs.uToast.show({
                    type'success',
                    title'登录成功',
                    url'/pages/miniapp/index',
                    isTabtrue
                  });
                });
              });
            }
          });
        },
        fail(err) {
          wx.login({
            successres => {
              that.form.code = res.code
            }
          });
        }
      });
    },
    toPage(url) {
      this.$u.route({
        url: url
      })
    }
  }
};
</script>

<style lang="scss" scoped>
</style>

【SpringBoot学习】38、SpringBoot 集成 wxJava 微信小程序:授权登录【SpringBoot学习】38、SpringBoot 集成 wxJava 微信小程序:授权登录

微信公众号


原文始发于微信公众号(花海里):【SpringBoot学习】38、SpringBoot 集成 wxJava 微信小程序:授权登录

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/69603.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!