微信小程序基于微信进行开发,而微信又存有用户信息,我们是否可以直接通过微信端获取用户信息,则无需用户进行再次输入个人信息。
微信小程序可以通过wx.getUserInfo()接口来获取部分用户信息,我们可以参考微信文档之wx.getUserInfo()。
但是通过该接口能获取的数据只有:
// 必须是在用户已经授权的情况下调用
wx.getUserInfo({
success(res) {
const userInfo = res.userInfo //整体user对象
const nickName = userInfo.nickName //用户昵称
const avatarUrl = userInfo.avatarUrl //用户头像
const gender = userInfo.gender // 性别 0:未知、1:男、2:女
const province = userInfo.province //用户国家
const city = userInfo.city //用户所在城市
const country = userInfo.country
}
})
但是如果我们要获取用户在该程序的唯一性标志openid,又或者用户在所有微信小程序的唯一性标志unionid,则无法直接通过该接口获取。另外,wx.getUserInfo()接口经过改版,无法一登录就会弹窗让用户授权,现在要通过编程设置按钮引导用户点击获取用户信息,这样子的改版被很多程序猿吐槽,我们也看看官方说明。
在解决新版本带来的问题之前,我们先来说一下除了这些基本用户信息以外,openid和unionid也是很多微信小程序所要获得存储的,先来说明一下两个id的含义:
(1) openid:一个用户在一个微信小程序下都有唯一标志,这个标志是证明该用户在该小程序的唯一性存在的标志。小程序可以通过获取openid来确定该用户在小程序中的身份
(2)unionid:微信下不同产品(如公众号和小程序),用户在不同产品下都有着唯一性的标志unionid,我们可以通过该标志确定用户在不同产品下唯一身份,这样就打通所有的小程序和公众号的账号系统。小程序可以通过获取unionid来绑定自身公众号,而用户要支付等操作时也需要有unionid的证明。
获取用户普通信息(就是昵称这类)虽然受到改版影响,但是实际上获取困难性并无增加多少,只需要通过设置按钮通过点击按钮事件触发wx.getUserInfo()j即可。而两个私密id才是这次获取困难性的来源。当然,在说明获取两个id的时候也会讲解一下获取用户普通信息。
在说明获取用户openid和unionid之前,我们先说一下微信小程序在我们建立程序的时候给的标准模板,该模板里面就是设置有按钮和获取用户信息的代码,而且我们可以通过查看简书文章:微信小程序登陆个人信息授权app与page的执行顺序先了解一下该小程序模板运行的模式。但是该模板中没有说明如何获取openid和unionid,而且没有和数据库后端交互。
(重点关注下面内容)
获取了用户的unionid的过程中自然要获取用户的openid,我们可以查看掘金:微信小程序之获取并解密用户数据(获取 openId、unionId),文章是17年编写的,当时版本还未改变,所以里面微信小程序的操作时不起作用的。但是在后端使用spring boot进行操作的过程是可以借鉴的。
unionid的获取是要先通过wx.login()接口(可通过微信小程序文档查看)获取code,发送get请求到微信小程序后端获取openid和session_key,这时候就获得了openid了,但是unionid作为更为隐秘的信息,则这时候是还未获得的。这时候我们就要再通过wx.getUserInfo()获取encryptedData和iv(查看微信小程序文档),其中encryptedData封装了用户信息和unionid(查看微信小程序文档),但是使用了AES进行加密,这时候我们要将encryptedData和iv发送到后端进行AES解密出unionid进行存储即可。
在掘金文章中并没有说明其中要导入了两个依赖,这里说明一下:
org.bouncycastle
bcprov-jdk15on
1.61
net.sf.json-lib
json-lib
2.4
jdk15
在掘金文章中是将wx.getUserInfo()封装在wx.login()中,而该方法是在小程序运行开始即进行,则在新版小程序是不一样的,我们应该先在app.js中先进行wx.login()获取code和openid发送到后台进行存储, 而在设置按钮的js文件中才进行wx.getUserInfo()获取encryptedData和iv进行解密获得unionid。
由于我并不需要确定用户在不同小程序和公众号之间的唯一性,而我只需要确定用户在我程序中的唯一性,即只需要获得openid进行存储即可。所以我通过上面掘金文章解决方法说一下获取用户openid的过程:
小程序中app.js中onLaunch()中进行设置:
onLaunch: function () {
// 登录
wx.login({
success: function (r) {
//获取code
var code = r.code;
//debugger;
if (code) {
//发送code到后台,分析openid
wx.request({
url: 'http://xxxxxx/login/regist?code=' + code,
method: 'POST',
header: {
'content-type': 'application/json'
},
success: function (res) {
//debugger;
if (res.data.status == 0) {
//status为空时登录凭证code为空
wx.showToast({
title: '登录凭证code为空...',
icon: "none",
duration: 2500
})
} else if (res.data.status == 1) {
//status为1时openid已存在
this.globalData.userInfo=res.data.userInfo;
console.log(userInfo);
} else if (res.data.status == 2) {
//status为2时openid不存在
this.globalData.userInfo=res.data.userInfo;
console.log(userInfo);
}
}
})
}
}
})
}
后端controller的编写:
import com.xie.video.entity.Users;
import com.xie.video.service.UsersService;
import com.xie.video.untils.HttpRequest;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/login")
public class LoginController {
@Autowired
private UsersService usersService;
@PostMapping("/regist")
public Map gettingOpenID(@RequestParam("code") String code){
Map map=new HashMap();
//登录凭证不能为空
if (code == null || code.length() == 0) {
map.put("status", 0);
map.put("msg", "code 不能为空");
return map;
}
//小程序唯一标识 (在微信小程序管理后台获取)
String wxspAppid = "xxxxx";
//小程序的 app secret (在微信小程序管理后台获取)
String wxspSecret = "xxxxx";
//授权(必填)
String grant_type = "authorization_code";
//////////////// 1、向微信服务器 使用登录凭证 code 获取 session_key 和 openid ////////////////
//请求参数
String params = "appid=" + wxspAppid + "&secret=" + wxspSecret + "&js_code=" + code + "&grant_type=" + grant_type;
//发送请求
String sr = HttpRequest.sendGet("https://api.weixin.qq.com/sns/jscode2session", params);
//解析相应内容(转换成json对象)
JSONObject json = JSONObject.fromObject(sr);
//用户的唯一标识(openid)
String openid = (String) json.get("openid");
//查询数据库中该openid是否存在
if(usersService.queryOpenIdIsExist(openid)){
//openid存在,则查找该user对象进行返回
Users users=usersService.queryUserByOpenID(openid);
//status为1,用户openid已存在
map.put("status", 1);
map.put("userInfo",users);
}else{
//openid不存在,则创建新user对象
Users users=new Users();
users.setOpenId(openid);
users=usersService.saveUsers(users);
//status为2,用户openid未存在
map.put("status", 2);
map.put("userInfo",users);
}
return map;
}
}
注意导入JSONObject的依赖(上面有说)
工具类HttpRequest(用于发送get或post请求)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
public class HttpRequest {
/**
* 向指定URL发送GET方法的请求
*
* @param url
* 发送请求的URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return URL 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param) {
String result = "";
BufferedReader in = null;
try {
String urlNameString = url + "?" + param;
URL realUrl = new URL(urlNameString);
// 打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
// 设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 建立实际的连接
connection.connect();
// 获取所有响应头字段
Map> map = connection.getHeaderFields();
// 遍历所有的响应头字段
for (String key : map.keySet()) {
System.out.println(key + "--->" + map.get(key));
}
// 定义 BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url
* 发送请求的 URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!"+e);
e.printStackTrace();
}
//使用finally块来关闭输出流、输入流
finally{
try{
if(out!=null){
out.close();
}
if(in!=null){
in.close();
}
}
catch(IOException ex){
ex.printStackTrace();
}
}
return result;
}
}
我们设置好数据库和持久层即可将数据存入数据库就完成了。