微信小程序 Java服务端 用户登录相关代码 工具类 2023
2023-04-26
阅读 {{counts.readCount}}
评论 {{counts.commentCount}}
## 前言
必须先吐槽下微信的神奇操作
[小程序用户头像昵称获取规则调整公告(微信开放社区)](https://developers.weixin.qq.com/community/develop/doc/00022c683e8a80b29bed2142b56c01)
我记得微信没多久之前刚改过一次,废弃了`wx.getUserInfo`,改成了`wx.getUserProfile`
这才没多久,又改了😂
![](https://s2.loli.net/2023/04/13/YJHnuRWL2FvMATh.gif)
<br>
最新的方式参考这个链接
[头像昵称填写(微信开放文档)](https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/userProfile.html)
可以理解为用户自行上传头像填写昵称,过程中允许直接使用微信头像和昵称。
<br>
## 代码
本文主要更新一下后端的工具类和接口的大致思路
<br>
依赖包括 `Apache HttpClient5` `FastJSON2` `SrpingBootRedis` 等
建议直接参考我之前的笔记
[Java Http请求工具类 基于最新版 HttpClient5 Fluent](https://leanote.zzzmh.cn/blog/post/64377742da74050013022f62)
[从零新建一个 Springboot 2.7.1 项目搭配 Swagger 3.0 Knife4j MyBatisPlus 等](https://leanote.zzzmh.cn/blog/post/admin/62d618a2da740500130121d2)
工具类
WechatUtils
```java
import com.alibaba.fastjson2.JSONObject;
import com.joinzs.auction.entity.wechat.PhoneInfo;
import com.joinzs.auction.exception.RRException;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* 微信核心工具类
*/
@Component
public class WechatUtils {
@Value("${wechat.miniapp.appid}")
private String miniAppAppid;
@Value("${wechat.miniapp.secret}")
private String miniAppSecret;
@Value("${wechat.miniapp.expire}")
private long expire;
@Autowired
private RedisUtils redisUtils;
public String getAccessToken() {
String accessToken = redisUtils.get("access_token_" + miniAppAppid);
if (StringUtils.isBlank(accessToken)) {
String url = "https://api.weixin.qq.com/cgi-bin/token" + "?"
+ "appid=" + miniAppAppid + "&secret=" + miniAppSecret + "&grant_type=client_credential";
JSONObject result = HttpClientUtils.doGet(url);
if (result != null && result.containsKey("access_token")) {
accessToken = result.getString("access_token");
Integer expires = result.getInteger("expires_in");
if (StringUtils.isNotBlank(accessToken) && expires != null) {
redisUtils.set("access_token_" + miniAppAppid, accessToken, expires);
}
}
}
if (StringUtils.isBlank(accessToken)) {
throw new RRException(700);
}
return accessToken;
}
/**
* 微信登录授权
* https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html
*/
public JSONObject getLoginInfo(String code) {
String url = "https://api.weixin.qq.com/sns/jscode2session?" +
"appid=" + miniAppAppid + "&secret=" + miniAppSecret +
"&js_code=" + code + "&grant_type=authorization_code";
//发送请求
JSONObject result = HttpClientUtils.doGet(url);
if (result != null && result.containsKey("openid")) {
String openid = result.getString("openid");
if (StringUtils.isNotBlank(openid)) {
String sha256 = DigestUtils.sha256Hex(openid);
redisUtils.set("login_" + sha256, openid, expire);
return JSONObject.of("openid", openid, "key", sha256);
}
}
throw new RRException(702);
}
/**
* 获取用户手机号
* https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-info/phone-number/getPhoneNumber.html
*/
public PhoneInfo getPhoneInfo(String code) {
String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + getAccessToken();
JSONObject result = HttpClientUtils.doPost(url, JSONObject.of("code", code));
if (result != null && result.getIntValue("errcode") == 0) {
return result.getObject("phone_info", PhoneInfo.class);
}
throw new RRException(703);
}
}
```
配置文件加这一段配置
替换成你自己的appid和secret
`application-dev.yml`
`application-prod.yml`
```yml
wechat:
miniapp:
appid: xxxxxxxxxxxx
secret: xxxxxxxxxxxx
expire: 7200
```
返回值实体类
`PhoneInfo.java`
```java
@Data
@ApiModel("微信用户手机号")
public class PhoneInfo {
String phoneNumber;
String purePhoneNumber;
Integer countryCode;
}
```
##思路
在Controller中
```java
@ApiOperation("微信登录")
@PostMapping("/login")
public JSONObject login(@RequestParam String code) {
// 先用code换openid
JSONObject login = wechatUtils.getLoginInfo(code);
// 再去数据库查openid是否存在
if(存在){
// 查看数据是否完整
if(完整){
// 登录成功直接发放token
}else{
// 继续完善信息
}
}else{
// 新增一条数据并完善信息
}
return JSONObject.of();
}
@ApiOperation("微信获取用户信息")
@PostMapping("/getUserInfo")
@Transactional(rollbackFor = Throwable.class)
public JSONObject getUserInfo(@RequestBody WechatForm form) {
// 上个接口的key去redis换openid
// 头像昵称是从前端直接传字符串和文件
// 手机号用前端code代入方法getPhoneInfo换
...
// 最后登录成功返回token
}
```
## END