小程序中自动获取手机号为很常见的一个功能点,可以减少用户输入,目前小程序规则是不允许系统直接自动获取,需要用户手动触发
本文中的实现方式:前端使用uniapp生成小程序,后端使用springboot
首先,上效果图:
1、前端uniapp代码
小程序原生代码类似,可以看微信开放平台官网示例
<u-form-item :label-position="labelPosition"
label="手机号码" prop="phone" label-width="150">
<u-input :border="border" placeholder="请输入手机号" v-model="model.phone" type="number" :disabled="false"></u-input>
<!-- #ifndef H5 -->
<u-button slot="right" type="success" size="mini" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">获取手机号
</u-button>
<!-- #endif -->
</u-form-item>
目前获取手机号不需要先做登录授权
// 获取微信小程序绑定的手机号
getPhoneNumber(e) {
let data1 = {};
data1.code = e.detail.code;
data1.iv=e.detail.iv;
data1.encryptedData=e.detail.encryptedData;
_this._post_form('system/phone', data1, (result) => {
if (result && result != null && result.code=='200'){
uni.setStorageSync('user_phone', result.data.phone);
console.info(result.data.phone);
_this.model.phone = result.data.phone;
}else{
uni.showModal({
showCancel: false,
title: '错误',
content: "获取手机号失败,请联系管理员处理",
});
}
});
}
2、后端代码
注意:
1、这里后端不再使用旧版的解密方式获取手机号,而是直接请求微信获取
相关说明见微信公众平台API说明
2、这里的代码,最有用的是,使用post请求的时候,参数需要为raw的形式,否则,微信会返回47001的错误
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.WxDecPhone;
import com.ruoyi.common.enums.BusinessType;
/**
* 获取微信手机号Controller
*
* @author
* @date 2022-03-23
*/
@RestController
@RequestMapping("/system/phone")
public class WxController extends BaseController {
// 小程序appid
@Value("${APP_ID}")
private String APP_ID;
// 小程序的app secret
@Value("${APPSECRET}")
private String APPSECRET;
@Log(title = "解密手机号", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult deciphering(@RequestBody WxDecPhone wxDecPhone) {
String code = wxDecPhone.getCode();//code 为getPhoneNumber(e)后的e.detail.code
String phone = "";
String access_token = getAccess_token();
System.out.println("code:" + code);
System.out.println("access_token:" + access_token);
String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + access_token;
JSONObject body = new JSONObject();
body.put("code", code);
try {
String ret = httpPostRaw(url, body.toString(), null, null);
if(ret != null && !"".equals(ret)) {
JSONObject json = JSONObject.parseObject(ret);
JSONObject phone_info = json.getJSONObject("phone_info");
phone = phone_info.getString("phoneNumber");
}
} catch (Exception e) {
e.printStackTrace();
}
Map<String, Object> data = new HashedMap<String, Object>();
data.put("phone", phone);
AjaxResult ajax = AjaxResult.success(data);
return ajax;
}
/**
* 微信接口请求令牌:生产环境下 要用redis缓存起来
* @return
*/
public String getAccess_token() {
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
+ APP_ID + "&secret=" + APPSECRET;
String accessToken = null;
try {
URL urlGet = new URL(url);
HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
http.setRequestMethod("GET"); // 必须是get方式请求
http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
http.connect();
InputStream is = http.getInputStream();
int size = is.available();
byte[] jsonBytes = new byte[size];
is.read(jsonBytes);
String message = new String(jsonBytes, "UTF-8");
JSONObject demoJson = JSONObject.parseObject(message);
accessToken = demoJson.getString("access_token");
is.close();
} catch (Exception e) {
e.printStackTrace();
}
return accessToken;
}
/**
* 参数以raw的方式做post请求
*
* @param url
* @param stringJson
* @param headers
* @param encode
* @return
*/
public static String httpPostRaw(String url, String stringJson, Map<String, String> headers, String encode) {
String str = "";
if (encode == null) {
encode = "utf-8";
}
// HttpClients.createDefault()等价于 HttpClientBuilder.create().build();
CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
HttpPost httpost = new HttpPost(url);
// 设置header
httpost.setHeader("Content-type", "application/json");
if (headers != null && headers.size() > 0) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
httpost.setHeader(entry.getKey(), entry.getValue());
}
}
// 组织请求参数
StringEntity stringEntity = new StringEntity(stringJson, encode);
httpost.setEntity(stringEntity);
String content = null;
CloseableHttpResponse httpResponse = null;
try {
// 响应信息
httpResponse = closeableHttpClient.execute(httpost);
HttpEntity entity = httpResponse.getEntity();
content = EntityUtils.toString(entity, encode);
System.out.println(content);
str = content;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
httpResponse.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try { // 关闭连接、释放资源
closeableHttpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
}