寫在前面
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 爲:
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:
//app.js
App({
globalData: {
userInfo: null
}
})
<!--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>
.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;
}
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。
Servlet
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 一萬遍!因爲比較長,很容易拼錯。