文章目录
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());
//g.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(entity.getNickName())
.setDeptId(0L)
.setPassword(defaultPassword)
.setPhonenumber(phoneNoInfo.getPhoneNumber())
.setAvatar(entity.getAvatarUrl());
handleUseSex(entity, 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(entity.getNickName());
sysUser.setAvatar(entity.getAvatarUrl());
handleUseSex(entity, 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());
}
}
private void handleUseSex(WxLoginVo userInfo, SysUser user) {
// 微信:性别 0:未知、1:男、2:女
if (userInfo.getGender() == 0) {
user.setSex("2");
} else if (userInfo.getGender() == 1) {
user.setSex("0");
} else if (userInfo.getGender() == 2) {
user.setSex("1");
}
}
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.appuser.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;
/**
* 用户昵称
*/
private String nickName;
/**
* 用户头像
*/
private String avatarUrl;
/**
* 用户性别
*/
private int gender;
}
OK ,到此后端调用逻辑都完成了
5、uniapp 前端
<template>
<view>
<view style="padding: 15px;">
<view class="global-btn">
<u-icon size="72" name="weixin-fill" color="rgb(83,194,64)"></u-icon>
<u-button type="primary" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
<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>
</view>
</template>
<script>
let that;
export default {
data() {
return {
baseUrl: this.$config.baseUrl,
form: {
// 换取openId
code: '',
// 解密手机号
rawData: '',
signature: '',
encryptedData: '',
iv: '',
// 用户信息
nickName: '',
avatarUrl: '',
gender: '',
}
}
},
onLoad() {
that = this;
that.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获取失败');
},
});
},
getUserInfo(e) {
console.log(e);
},
getPhoneNumber(e) {
that.getCode();
if (e.detail.errMsg != 'getPhoneNumber:ok') {
that.$msg('未授权手机号');
return false;
}
that.form.encryptedData = e.detail.encryptedData;
that.form.iv = e.detail.iv;
// 检查登录态是否过期
wx.checkSession({
success() {
// 用户信息
wx.getUserInfo({
success: function(result) {
that.form.rawData = result.rawData;
that.form.signature = result.signature;
that.form.nickName = result.userInfo.nickName;
that.form.avatarUrl = result.userInfo.avatarUrl;
that.form.gender = result.userInfo.gender;
uni.$u.http.post('/au/weiXin/login', that.form).then(res => {
uni.setStorageSync(that.$config.cachePrefix + 'token', res.token);
uni.$u.http.get('/au/weiXin/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);
uni.$u.route({type: 'tab', url: '/pages/index/index'});
});
});
}
});
},
fail(err) {
wx.login({
success: res => {
that.form.code = res.code
}
});
}
});
},
toPage(url) {
this.$u.route({
url: url
})
}
}
};
</script>
<style lang="scss" scoped>
</style>
版权声明:本文为qq_38762237原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。