写在前面

Client: 微信小程序

Server: Java Servlet running on local Tomcat 9.0

Tools: 微信开发者工具 && Eclipse

获取思路

参考试水微信小程序与Java后台通信一文,我们可以快速建立起小程序与 Java 后台之间的通信。而获取 openid 之前,我们首先要知道微信小程序官方如何定义 openid 的工作机制。参考微信小程序公众平台的开发文档:小程序登录,可以得知 openid 的工作机制主要为下图所示:

由此可以得知小程序若想在后台获取到 openid 就必须在前端发送一个临时生成的 code 到 Java 后台,然后 Java 后台使用 code 向微信相关 API 请求并获得 session_key 以及 openid。请求的 API 为:

1
https://api.weixin.qq.com/sns/jscode2session?appid=xxx&secret=xxx&js_code=xxx&grant_type=authorization_code

其中 appid 和 secret 秘钥需要在开发者平台的开发设置中获取,且 secret 秘钥不会明文保存,生成后记得保存下来,否则如果忘记需要重新生成。js_code 则是小程序传回的临时 code。

小程序端

小程序端制作一个简单的测试界面,并在 js 中向后台发送生成的 code:

1
2
3
4
5
6
//app.js
App({
globalData: {
userInfo: null
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!--index.wxml-->
<view>
<view class="userinfo">
<block wx:if="{{!hasUserInfo && canIUse}}">
<image class="userinfo-avatar" src="{{usernoneSrc}}" mode="cover"></image>
<button open-type="getUserInfo" bindgetuserinfo="getUserInfo" style='margin-bottom:50rpx' bindtap="login"> 点击授权 </button>
</block>
<block wx:else>
<image class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
</block>
</view>
<view class="vipText">
<block wx:if="{{vipFlag}}">
<text style='color:orange;border:1px solid orange;border-radius:25%;'>vip</text>
</block>
<block wx:else>
<text style='color:#eee;border:1px solid #eee;border-radius: 25%;'>vip</text>
</block>
</view>
</view>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.userinfo {
display: flex;
flex-direction: column;
align-items: center;
border-bottom: 2px solid #eee;
}

.userinfo-avatar {
width: 200rpx;
height: 200rpx;
margin: 50rpx;
border-radius: 50%;
border: 1px solid #eee;
}

.userinfo-nickname {
color: #aaa;
font-size: 60rpx;
margin-bottom: 50rpx;
}

.vipText {
width: 100%;
text-align: center;
margin-top: 50rpx;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
const app = getApp()

Page({
data: {
userInfo: {},
usernoneSrc: "/images/user.png",
//vipFlag: true,
hasUserInfo: false,
canIUse: wx.canIUse('button.open-type.getUserInfo')
},
//登录获取code
login: function () {
wx.login({
success: function (res) {
//发送请求
wx.request({
url: 'http://localhost:8080/smallAPP/ConnectTest', //接口地址
data: { code: res.code },
header: {
'content-type': 'application/x-www-form-urlencoded'
},
success: function (res) {
console.log(res.data);
},
fail: function (res) {
console.log("Fail to connect...");
}
})
}
})
},
onLoad: function () {
if (app.globalData.userInfo) {
this.setData({
userInfo: app.globalData.userInfo,
hasUserInfo: true
})
} else if (this.data.canIUse) {
// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
app.userInfoReadyCallback = res => {
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
} else {
// 在没有 open-type=getUserInfo 版本的兼容处理
wx.getUserInfo({
success: res => {
app.globalData.userInfo = res.userInfo
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
})
}
},
getUserInfo: function (e) {
console.log(e)
app.globalData.userInfo = e.detail.userInfo
this.setData({
userInfo: e.detail.userInfo,
hasUserInfo: true
})
}
})

界面如下:

Server

lib

除了试水微信小程序与Java后台通信一文中的 json 相关包,我们还需要导入一个用于进行 Http 请求的 Apache 的工具:HttpClient。该工具本来位于 Apache 的 Commons 项目中,但是后来置于 Apache 的 HttpComponents 项目中了,具体说明详见 Apache Commons 以及 Jakarta Commons HttpClient

Download HttpClient

Servlet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package com.smallAPP.common;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import net.sf.json.JSONObject;

@WebServlet("/ConnectTest")
public class ConnectTest extends HttpServlet {
private static final long serialVersionUID = 1L;
public ConnectTest() {
super();
}

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {//设置请求编码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");

String code = request.getParameter("code");
System.out.println(code);

String appSecret = "对应secret秘钥";
String appId = "对应APPID";

if (code != null) {
//获取openid和access_token的连接
String getOpenIdUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appId +"&secret=" + appSecret + "&js_code=" + code +"&grant_type=authorization_code";
System.out.println(getOpenIdUrl);
//获取返回的code
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(getOpenIdUrl);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
//向微信发送请求并获取response
String responseBody = httpClient.execute(httpGet,responseHandler);
System.out.println("=========================获取token===================");
System.out.println(responseBody);
JSONObject jsonObject = JSONObject.fromObject(responseBody);
System.out.println(jsonObject.toString());
}

//转成json数据
Map<String, Object> result = new HashMap<String, Object>();
result.put("data", code);
result.put("msg", "后台已收到");
JSONObject object = JSONObject.fromObject(result);
PrintWriter out = response.getWriter();
out.print(object.toString());
out.close();
}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}

测试

在小程序界面点击绑定了发送 code 代码的按钮后,小程序端获取授权以及用户头像等基本信息,如下图:

此时观察后台的结果,看是否获取到 openid:

如上图所示已经成功获取了 openid。

一些坑

  • HttpClient 这个工具包已经换位置了。
  • 如果请求返回有错误,请检查请求的 API 一万遍!因为比较长,很容易拼错。